xref: /haiku/src/add-ons/translators/jpeg2000/JPEG2000Translator.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2 
3 Copyright (c) 2003, Marcin 'Shard' Konicki
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9     * Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright notice,
12       this list of conditions and the following disclaimer in the documentation and/or
13       other materials provided with the distribution.
14     * Name "Marcin Konicki", "Shard" or any combination of them,
15       must not be used to endorse or promote products derived from this
16       software without specific prior written permission from Marcin Konicki.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 */
31 
32 
33 #include "JPEG2000Translator.h"
34 #include "jp2_cod.h"
35 #include "jpc_cs.h"
36 
37 #include <TabView.h>
38 
39 
40 // Set these accordingly
41 #define JP2_ACRONYM "JP2"
42 #define JP2_FORMAT 'JP2 '
43 #define JP2_MIME_STRING "image/jp2"
44 #define JP2_DESCRIPTION "JPEG2000 image"
45 
46 // The translation kit's native file type
47 #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
48 #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap image"
49 
50 // Translation Kit required globals
51 char translatorName[] = "JPEG2000 Images";
52 char translatorInfo[] = "©2002-2003, Shard\n"
53 	"©2005-2006, Haiku\n"
54 	"\n"
55 	"Based on JasPer library:\n"
56 	"© 1999-2000, Image Power, Inc. and\n"
57 	"the University of British Columbia, Canada.\n"
58 	"© 2001-2003 Michael David Adams.\n"
59 	"          http://www.ece.uvic.ca/~mdadams/jasper/\n"
60 	"\n"
61 	"ImageMagick's jp2 codec was used as \"tutorial\".\n"
62 	"          http://www.imagemagick.org/\n";
63 
64 int32 translatorVersion = 0x100;
65 
66 // Define the formats we know how to read
67 translation_format inputFormats[] = {
68 	{ JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
69 		JP2_MIME_STRING, JP2_DESCRIPTION },
70 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
71 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
72 	{},
73 };
74 
75 // Define the formats we know how to write
76 translation_format outputFormats[] = {
77 	{ JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
78 		JP2_MIME_STRING, JP2_DESCRIPTION },
79 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
80 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
81 	{},
82 };
83 
84 bool gAreSettingsRunning = false;
85 
86 
87 //!	Make settings to defaults
88 void
89 LoadDefaultSettings(jpeg_settings *settings)
90 {
91 	settings->Quality = 25;
92 	settings->JPC = false;
93 	settings->B_GRAY1_as_B_RGB24 = false;
94 	settings->B_GRAY8_as_B_RGB32 = true;
95 }
96 
97 
98 //!	Save settings to config file
99 void
100 SaveSettings(jpeg_settings *settings)
101 {
102 	// Make path to settings file
103 	BPath path;
104 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
105 		return;
106 
107 	path.Append(SETTINGS_FILE);
108 
109 	// Open settings file (create it if there's no file) and write settings
110 	FILE *file = NULL;
111 	if ((file = fopen(path.Path(), "wb+"))) {
112 		fwrite(settings, sizeof(jpeg_settings), 1, file);
113 		fclose(file);
114 	}
115 }
116 
117 
118 //!	Return true if settings were run, false if not
119 bool
120 SettingsChangedAlert()
121 {
122 	// If settings view wasn't already initialized (settings not running)
123 	// and user wants to run settings
124 	if (!gAreSettingsRunning && (new BAlert("Different settings file", "JPEG2000 settings were set to default because of incompatible settings file.", "Configure settings", "OK", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 0) {
125 		// Create settings window (with no quit on close!), launch it and wait until it's closed
126 		status_t err;
127 		TranslatorWindow *window = new TranslatorWindow(false);
128 		window->Show();
129 		wait_for_thread(window->Thread(), &err);
130 		return true;
131 	}
132 
133 	return false;
134 }
135 
136 
137 /*!
138 	Load settings from config file
139 	If can't find it make them default and try to save
140 */
141 void
142 LoadSettings(jpeg_settings *settings)
143 {
144 	// Make path to settings file
145 	BPath path;
146 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) {
147 		LoadDefaultSettings(settings);
148 		return;
149 	}
150 
151 	path.Append(SETTINGS_FILE);
152 
153 	// Open settings file (create it if there's no file) and write settings
154 	FILE *file = NULL;
155 	if ((file = fopen(path.Path(), "rb"))) {
156 		if (!fread(settings, sizeof(jpeg_settings), 1, file)) {
157 			// settings struct has changed size
158 			// Load default settings, and Save them
159 			fclose(file);
160 			LoadDefaultSettings(settings);
161 			SaveSettings(settings);
162 			// Tell user settings were changed to default, and ask to run settings panel or not
163 			if (SettingsChangedAlert())
164 				// User configured settings, load them again
165 				LoadSettings(settings);
166 		} else
167 			fclose(file);
168 	} else if ((file = fopen(path.Path(), "wb+"))) {
169 		LoadDefaultSettings(settings);
170 		fwrite(settings, sizeof(jpeg_settings), 1, file);
171 		fclose(file);
172 		// Tell user settings were changed to default, and ask to run settings panel or not
173 		if (SettingsChangedAlert())
174 			// User configured settings, load them again
175 			LoadSettings(settings);
176 	}
177 }
178 
179 
180 //	#pragma mark - conversion routines
181 
182 
183 //!	Make RGB32 scanline from *pixels[3]
184 inline void
185 read_rgb24_to_rgb32(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
186 {
187 	int32 index = 0;
188 	int32 x = 0;
189 	while (x < width) {
190 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[2], x);
191 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[1], x);
192 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[0], x);
193 		scanline[index++] = 255;
194 		x++;
195 	}
196 }
197 
198 
199 //!	Make gray scanline from *pixels[1]
200 inline void
201 read_gray_to_rgb32(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
202 {
203 	int32 index = 0;
204 	int32 x = 0;
205 	jpr_uchar_t color = 0;
206 	while (x < width) {
207 		color = (jpr_uchar_t)jas_matrix_getv(pixels[0], x++);
208 		scanline[index++] = color;
209 		scanline[index++] = color;
210 		scanline[index++] = color;
211 		scanline[index++] = 255;
212 	}
213 }
214 
215 
216 /*!
217 	Make RGBA32 scanline from *pixels[4]
218 	(just read data to scanline)
219 */
220 inline void
221 read_rgba32(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
222 {
223 	int32 index = 0;
224 	int32 x = 0;
225 	while (x < width) {
226 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[2], x);
227 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[1], x);
228 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[0], x);
229 		scanline[index++] = (jpr_uchar_t)jas_matrix_getv(pixels[3], x);
230 		x++;
231 	}
232 }
233 
234 
235 /*!
236 	Make gray scanline from *pixels[1]
237 	(just read data to scanline)
238 */
239 inline void
240 read_gray(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
241 {
242 	int32 x = 0;
243 	while (x < width) {
244 		scanline[x] = (jpr_uchar_t)jas_matrix_getv(pixels[0], x);
245 		x++;
246 	}
247 }
248 
249 
250 //!	Make *pixels[1] from gray1 scanline
251 inline void
252 write_gray1_to_gray(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
253 {
254 	int32 x = 0;
255 	int32 index = 0;
256 	while (x < (width/8)) {
257 		unsigned char c = scanline[x++];
258 		for (int b = 128; b; b = b >> 1) {
259 			if (c & b)
260 				jas_matrix_setv(pixels[0], index++, 0);
261 			else
262 				jas_matrix_setv(pixels[0], index++, 255);
263 		}
264 	}
265 }
266 
267 
268 //!	Make *pixels[3] from gray1 scanline
269 inline void
270 write_gray1_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
271 {
272 	int32 x = 0;
273 	int32 index = 0;
274 	while (x < (width/8)) {
275 		unsigned char c = scanline[x++];
276 		for (int b = 128; b; b = b >> 1) {
277 			if (c & b) {
278 				jas_matrix_setv(pixels[0], index, 0);
279 				jas_matrix_setv(pixels[1], index, 0);
280 				jas_matrix_setv(pixels[2], index, 0);
281 			} else {
282 				jas_matrix_setv(pixels[0], index, 255);
283 				jas_matrix_setv(pixels[1], index, 255);
284 				jas_matrix_setv(pixels[2], index, 255);
285 			}
286 			index++;
287 		}
288 	}
289 }
290 
291 
292 //!	Make *pixels[3] from cmap8 scanline
293 inline void
294 write_cmap8_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
295 {
296 	const color_map *map = system_colors();
297 	int32 x = 0;
298 	while (x < width) {
299 		rgb_color color = map->color_list[scanline[x]];
300 
301 		jas_matrix_setv(pixels[0], x, color.red);
302 		jas_matrix_setv(pixels[1], x, color.green);
303 		jas_matrix_setv(pixels[2], x, color.blue);
304 		x++;
305 	}
306 }
307 
308 
309 /*!
310 	Make *pixels[1] from gray scanline
311 	(just write data to pixels)
312 */
313 inline void
314 write_gray(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
315 {
316 	int32 x = 0;
317 	while (x < width) {
318 		jas_matrix_setv(pixels[0], x, scanline[x]);
319 		x++;
320 	}
321 }
322 
323 
324 /*!
325 	Make *pixels[3] from RGB15/RGBA15 scanline
326 	(just write data to pixels)
327 */
328 inline void
329 write_rgb15_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
330 {
331 	int32 x = 0;
332 	int32 index = 0;
333 	int16 in_pixel;
334 	while (x < width) {
335 		in_pixel = scanline[index] | (scanline[index+1] << 8);
336 		index += 2;
337 
338 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12));
339 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7));
340 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2));
341 		x++;
342 	}
343 }
344 
345 
346 /*!
347 	Make *pixels[3] from RGB15/RGBA15 bigendian scanline
348 	(just write data to pixels)
349 */
350 inline void
351 write_rgb15b_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
352 {
353 	int32 x = 0;
354 	int32 index = 0;
355 	int16 in_pixel;
356 	while (x < width) {
357 		in_pixel = scanline[index+1] | (scanline[index] << 8);
358 		index += 2;
359 
360 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7) | (((in_pixel & 0x7c00)) >> 12));
361 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2) | (((in_pixel & 0x3e0)) >> 7));
362 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2));
363 		x++;
364 	}
365 }
366 
367 
368 /*!
369 	Make *pixels[3] from RGB16/RGBA16 scanline
370 	(just write data to pixels)
371 */
372 inline void
373 write_rgb16_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
374 {
375 	int32 x = 0;
376 	int32 index = 0;
377 	int16 in_pixel;
378 	while (x < width) {
379 		in_pixel = scanline[index] | (scanline[index+1] << 8);
380 		index += 2;
381 
382 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0x7c00)) >> 12));
383 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9));
384 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2));
385 		x++;
386 	}
387 }
388 
389 
390 /*!
391 	Make *pixels[3] from RGB16/RGBA16 bigendian scanline
392 	(just write data to pixels)
393 */
394 inline void
395 write_rgb16b_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
396 {
397 	int32 x = 0;
398 	int32 index = 0;
399 	int16 in_pixel;
400 	while (x < width) {
401 		in_pixel = scanline[index+1] | (scanline[index] << 8);
402 		index += 2;
403 
404 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8) | (((in_pixel & 0xf800)) >> 13));
405 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3) | (((in_pixel & 0x7e0)) >> 9));
406 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3) | (((in_pixel & 0x1f)) >> 2));
407 		x++;
408 	}
409 }
410 
411 
412 /*!
413 	Make *pixels[3] from RGB24 scanline
414 	(just write data to pixels)
415 */
416 inline void
417 write_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
418 {
419 	int32 index = 0;
420 	int32 x = 0;
421 	while (x < width) {
422 		jas_matrix_setv(pixels[2], x, scanline[index++]);
423 		jas_matrix_setv(pixels[1], x, scanline[index++]);
424 		jas_matrix_setv(pixels[0], x, scanline[index++]);
425 		x++;
426 	}
427 }
428 
429 
430 /*!
431 	Make *pixels[3] from RGB24 bigendian scanline
432 	(just write data to pixels)
433 */
434 inline void
435 write_rgb24b(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
436 {
437 	int32 index = 0;
438 	int32 x = 0;
439 	while (x < width) {
440 		jas_matrix_setv(pixels[0], x, scanline[index++]);
441 		jas_matrix_setv(pixels[1], x, scanline[index++]);
442 		jas_matrix_setv(pixels[2], x, scanline[index++]);
443 		x++;
444 	}
445 }
446 
447 
448 /*!
449 	Make *pixels[3] from RGB32 scanline
450 	(just write data to pixels)
451 */
452 inline void
453 write_rgb32_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
454 {
455 	int32 index = 0;
456 	int32 x = 0;
457 	while (x < width) {
458 		jas_matrix_setv(pixels[2], x, scanline[index++]);
459 		jas_matrix_setv(pixels[1], x, scanline[index++]);
460 		jas_matrix_setv(pixels[0], x, scanline[index++]);
461 		index++;
462 		x++;
463 	}
464 }
465 
466 
467 /*!
468 	Make *pixels[3] from RGB32 bigendian scanline
469 	(just write data to pixels)
470 */
471 inline void
472 write_rgb32b_to_rgb24(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
473 {
474 	int32 index = 0;
475 	int32 x = 0;
476 	while (x < width) {
477 		index++;
478 		jas_matrix_setv(pixels[0], x, scanline[index++]);
479 		jas_matrix_setv(pixels[1], x, scanline[index++]);
480 		jas_matrix_setv(pixels[2], x, scanline[index++]);
481 		x++;
482 	}
483 }
484 
485 
486 /*!
487 	Make *pixels[4] from RGBA32 scanline
488 	(just write data to pixels)
489 	!!! UNTESTED !!!
490 */
491 inline void
492 write_rgba32(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
493 {
494 	int32 index = 0;
495 	int32 x = 0;
496 	while (x < width) {
497 		jas_matrix_setv(pixels[3], x, scanline[index++]);
498 		jas_matrix_setv(pixels[2], x, scanline[index++]);
499 		jas_matrix_setv(pixels[1], x, scanline[index++]);
500 		jas_matrix_setv(pixels[0], x, scanline[index++]);
501 		x++;
502 	}
503 }
504 
505 
506 /*!
507 	Make *pixels[4] from RGBA32 bigendian scanline
508 	(just write data to pixels)
509 	!!! UNTESTED !!!
510 */
511 inline void
512 write_rgba32b(jas_matrix_t **pixels, jpr_uchar_t *scanline, int width)
513 {
514 	int32 index = 0;
515 	int32 x = 0;
516 	while (x < width)
517 	{
518 		jas_matrix_setv(pixels[0], x, scanline[index++]);
519 		jas_matrix_setv(pixels[1], x, scanline[index++]);
520 		jas_matrix_setv(pixels[2], x, scanline[index++]);
521 		jas_matrix_setv(pixels[3], x, scanline[index++]);
522 		x++;
523 	}
524 }
525 
526 
527 //	#pragma mark -	jasper I/O
528 
529 
530 static int
531 Read(jas_stream_obj_t *object, char *buffer, const int length)
532 {
533 	return (*(BPositionIO**)object)->Read(buffer, length);
534 }
535 
536 
537 static int
538 Write(jas_stream_obj_t *object, char *buffer, const int length)
539 {
540 	return (*(BPositionIO**)object)->Write(buffer, length);
541 }
542 
543 
544 static long
545 Seek(jas_stream_obj_t *object, long offset, int origin)
546 {
547 	return (*(BPositionIO**)object)->Seek(offset, origin);
548 }
549 
550 
551 static int
552 Close(jas_stream_obj_t *object)
553 {
554 	return 0;
555 }
556 
557 
558 static jas_stream_ops_t positionIOops = {
559 	Read,
560 	Write,
561 	Seek,
562 	Close
563 };
564 
565 
566 static jas_stream_t *
567 jas_stream_positionIOopen(BPositionIO *positionIO)
568 {
569 	jas_stream_t *stream;
570 
571 	stream = (jas_stream_t *)malloc(sizeof(jas_stream_t));
572 	if (stream == (jas_stream_t *)NULL)
573 		return (jas_stream_t *)NULL;
574 
575 	memset(stream, 0, sizeof(jas_stream_t));
576 	stream->rwlimit_ = -1;
577 	stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*));
578 	if (stream->obj_ == (jas_stream_obj_t *)NULL)
579 		return (jas_stream_t *)NULL;
580 
581 	*((BPositionIO**)stream->obj_) = positionIO;
582 	stream->ops_ = (&positionIOops);
583 	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
584 	stream->bufbase_ = stream->tinybuf_;
585 	stream->bufsize_ = 1;
586 	stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
587 	stream->ptr_ = stream->bufstart_;
588 	stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
589 
590 	return stream;
591 }
592 
593 
594 //	#pragma mark - SView
595 
596 
597 SView::SView(const char *name, float x, float y)
598 	: BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW)
599 {
600 	fPreferredWidth = 0;
601 	fPreferredHeight = 0;
602 
603 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
604 	SetLowColor(ViewColor());
605 
606 	SetFont(be_plain_font);
607 }
608 
609 
610 void
611 SView::GetPreferredSize(float* _width, float* _height)
612 {
613 	if (_width)
614 		*_width = fPreferredWidth;
615 	if (_height)
616 		*_height = fPreferredHeight;
617 }
618 
619 
620 void
621 SView::ResizeToPreferred()
622 {
623 	ResizeTo(fPreferredWidth, fPreferredHeight);
624 }
625 
626 
627 void
628 SView::ResizePreferredBy(float width, float height)
629 {
630 	fPreferredWidth += width;
631 	fPreferredHeight += height;
632 }
633 
634 
635 void
636 SView::AddChild(BView *child, BView *before)
637 {
638 	BView::AddChild(child, before);
639 	child->ResizeToPreferred();
640 	BRect frame = child->Frame();
641 
642 	if (frame.right > fPreferredWidth)
643 		fPreferredWidth = frame.right;
644 	if (frame.bottom > fPreferredHeight)
645 		fPreferredHeight = frame.bottom;
646 }
647 
648 
649 //	#pragma mark -
650 
651 
652 SSlider::SSlider(BRect frame, const char *name, const char *label,
653 		BMessage *message, int32 minValue, int32 maxValue, orientation posture,
654 		thumb_style thumbType, uint32 resizingMode, uint32 flags)
655 	: BSlider(frame, name, label, message, minValue, maxValue,
656 		posture, thumbType, resizingMode, flags)
657 {
658 	rgb_color barColor = { 0, 0, 229, 255 };
659 	UseFillColor(true, &barColor);
660 }
661 
662 
663 //!	Update status string - show actual value
664 char*
665 SSlider::UpdateText() const
666 {
667 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value());
668 	return fStatusLabel;
669 }
670 
671 
672 //!	BSlider::ResizeToPreferred + Resize width if it's too small to show label and status
673 void
674 SSlider::ResizeToPreferred()
675 {
676 	int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999"));
677 	if (width < 230)
678 		width = 230;
679 
680 	float w, h;
681 	GetPreferredSize(&w, &h);
682 	ResizeTo(width, h);
683 }
684 
685 
686 //	#pragma mark -
687 
688 
689 TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings,
690 		float x, float y)
691 	: SView(name, x, y),
692 	fSettings(settings)
693 {
694 	fGrayAsRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
695 		GetPreferredHeight()), "grayasrgb32", VIEW_LABEL_GRAYASRGB32,
696 		new BMessage(VIEW_MSG_SET_GRAYASRGB32));
697 	fGrayAsRGB32->SetFont(be_plain_font);
698 	if (fSettings->B_GRAY8_as_B_RGB32)
699 		fGrayAsRGB32->SetValue(1);
700 
701 	AddChild(fGrayAsRGB32);
702 
703 	ResizeToPreferred();
704 }
705 
706 
707 void
708 TranslatorReadView::AttachedToWindow()
709 {
710 	fGrayAsRGB32->SetTarget(this);
711 }
712 
713 
714 void
715 TranslatorReadView::MessageReceived(BMessage *message)
716 {
717 	switch (message->what) {
718 		case VIEW_MSG_SET_GRAYASRGB32:
719 		{
720 			int32 value;
721 			if (message->FindInt32("be:value", &value) == B_OK) {
722 				fSettings->B_GRAY8_as_B_RGB32 = value;
723 				SaveSettings(fSettings);
724 			}
725 			break;
726 		}
727 		default:
728 			BView::MessageReceived(message);
729 			break;
730 	}
731 }
732 
733 
734 //	#pragma mark - TranslatorWriteView
735 
736 
737 TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings,
738 		float x, float y)
739 	: SView(name, x, y),
740 	fSettings(settings)
741 {
742 	fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10,
743 		GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY,
744 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
745 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
746 	fQualitySlider->SetHashMarkCount(10);
747 	fQualitySlider->SetLimitLabels("Low", "High");
748 	fQualitySlider->SetFont(be_plain_font);
749 	fQualitySlider->SetValue(fSettings->Quality);
750 	AddChild(fQualitySlider);
751 
752 	fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight() + 5, 25,
753 		GetPreferredHeight() + 5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24,
754 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
755 	fGrayAsRGB24->SetFont(be_plain_font);
756 	if (fSettings->B_GRAY1_as_B_RGB24)
757 		fGrayAsRGB24->SetValue(1);
758 
759 	AddChild(fGrayAsRGB24);
760 
761 	fCodeStreamOnly = new BCheckBox(BRect(10, GetPreferredHeight() + 5, 10,
762 		GetPreferredHeight()), "codestreamonly", VIEW_LABEL_JPC,
763 		new BMessage(VIEW_MSG_SET_JPC));
764 	fCodeStreamOnly->SetFont(be_plain_font);
765 	if (fSettings->JPC)
766 		fCodeStreamOnly->SetValue(1);
767 
768 	AddChild(fCodeStreamOnly);
769 
770 	ResizeToPreferred();
771 }
772 
773 
774 void
775 TranslatorWriteView::AttachedToWindow()
776 {
777 	fQualitySlider->SetTarget(this);
778 	fGrayAsRGB24->SetTarget(this);
779 	fCodeStreamOnly->SetTarget(this);
780 }
781 
782 
783 void
784 TranslatorWriteView::MessageReceived(BMessage *message)
785 {
786 	switch (message->what) {
787 		case VIEW_MSG_SET_QUALITY:
788 		{
789 			int32 value;
790 			if (message->FindInt32("be:value", &value) == B_OK) {
791 				fSettings->Quality = value;
792 				SaveSettings(fSettings);
793 			}
794 			break;
795 		}
796 		case VIEW_MSG_SET_GRAY1ASRGB24:
797 		{
798 			int32 value;
799 			if (message->FindInt32("be:value", &value) == B_OK) {
800 				fSettings->B_GRAY1_as_B_RGB24 = value;
801 				SaveSettings(fSettings);
802 			}
803 			break;
804 		}
805 		case VIEW_MSG_SET_JPC:
806 		{
807 			int32 value;
808 			if (message->FindInt32("be:value", &value) == B_OK) {
809 				fSettings->JPC = value;
810 				SaveSettings(fSettings);
811 			}
812 			break;
813 		}
814 		default:
815 			BView::MessageReceived(message);
816 			break;
817 	}
818 }
819 
820 
821 //	#pragma mark -
822 
823 
824 TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y)
825 	: SView(name, x, y)
826 {
827 	BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title",
828 		translatorName);
829 	title->SetFont(be_bold_font);
830 
831 	AddChild(title);
832 
833 	BRect rect = title->Bounds();
834 	float space = title->StringWidth("    ");
835 
836 	char versionString[16];
837 	sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8),
838 		(int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf));
839 
840 	BStringView *version = new BStringView(BRect(rect.right+space, rect.top,
841 		rect.right+space, rect.top), "Version", versionString);
842 	version->SetFont(be_plain_font);
843 	version->SetFontSize(9);
844 	// Make version be in the same line as title
845 	version->ResizeToPreferred();
846 	version->MoveBy(0, rect.bottom-version->Frame().bottom);
847 
848 	AddChild(version);
849 
850 	// Now for each line in translatorInfo add a BStringView
851 	char* current = translatorInfo;
852 	int32 index = 1;
853 	while (current != NULL && current[0]) {
854 		char text[128];
855 		char* newLine = strchr(current, '\n');
856 		if (newLine == NULL) {
857 			strlcpy(text, current, sizeof(text));
858 			current = NULL;
859 		} else {
860 			strlcpy(text, current, min_c((int32)sizeof(text), newLine + 1 - current));
861 			current = newLine + 1;
862 		}
863 
864 		BStringView* string = new BStringView(BRect(10, GetPreferredHeight(),
865 			10, GetPreferredHeight()), "copyright", text);
866 		if (index > 3)
867 			string->SetFontSize(9);
868 		AddChild(string);
869 
870 		index++;
871 	}
872 
873 	ResizeToPreferred();
874 }
875 
876 
877 //	#pragma mark -
878 
879 
880 TranslatorView::TranslatorView(const char *name)
881 	: SView(name),
882 	fTabWidth(30),
883 	fActiveChild(0)
884 {
885 	// Set global var to true
886 	gAreSettingsRunning = true;
887 
888 	// Load settings to global settings struct
889 	LoadSettings(&fSettings);
890 
891 	font_height fontHeight;
892 	GetFontHeight(&fontHeight);
893 	fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 7;
894 	// Add left and top margins
895 	float top = fTabHeight + 20;
896 	float left = 0;
897 
898 	// This will remember longest string width
899 	int32 nameWidth = 0;
900 
901 	SView *view = new TranslatorWriteView("Write", &fSettings, left, top);
902 	AddChild(view);
903 	nameWidth = (int32)StringWidth(view->Name());
904 	fTabs.AddItem(new BTab(view));
905 
906 	view = new TranslatorReadView("Read", &fSettings, left, top);
907 	AddChild(view);
908 	if (nameWidth < StringWidth(view->Name()))
909 		nameWidth = (int32)StringWidth(view->Name());
910 	fTabs.AddItem(new BTab(view));
911 
912 	view = new TranslatorAboutView("About", left, top);
913 	AddChild(view);
914 	if (nameWidth < StringWidth(view->Name()))
915 		nameWidth = (int32)StringWidth(view->Name());
916 	fTabs.AddItem(new BTab(view));
917 
918 	fTabWidth += nameWidth;
919 	if (fTabWidth * CountChildren() > GetPreferredWidth())
920 		ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0);
921 
922 	// Add right and bottom margins
923 	ResizePreferredBy(10, 15);
924 
925 	ResizeToPreferred();
926 
927 	// Make TranslatorView resize itself with parent
928 	SetFlags(Flags() | B_FOLLOW_ALL);
929 }
930 
931 
932 TranslatorView::~TranslatorView()
933 {
934 	gAreSettingsRunning = false;
935 
936 	BTab* tab;
937 	while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) {
938 		delete tab;
939 	}
940 }
941 
942 
943 //!	Attached to window - resize parent to preferred
944 void
945 TranslatorView::AttachedToWindow()
946 {
947 	// Hide all children except first one
948 	BView *child;
949 	int32 index = 1;
950 	while ((child = ChildAt(index++)) != NULL)
951 		child->Hide();
952 
953 }
954 
955 
956 BRect
957 TranslatorView::_TabFrame(int32 index) const
958 {
959 	return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight);
960 }
961 
962 
963 void
964 TranslatorView::Draw(BRect updateRect)
965 {
966 	// This is needed because DataTranslations app hides children
967 	// after user changes translator
968 	if (ChildAt(fActiveChild)->IsHidden())
969 		ChildAt(fActiveChild)->Show();
970 
971 	// Clear
972 	SetHighColor(ViewColor());
973 	BRect frame = _TabFrame(0);
974 	FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1));
975 
976 	int32 index = 0;
977 	BTab* tab;
978 	while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) {
979 		tab_position position;
980 		if (fActiveChild == index)
981 			position = B_TAB_FRONT;
982 		else if (index == 0)
983 			position = B_TAB_FIRST;
984 		else
985 			position = B_TAB_ANY;
986 
987 		tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild);
988 		index++;
989 	}
990 
991 	// Draw bottom edge
992 	SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT));
993 
994 	BRect selectedFrame = _TabFrame(fActiveChild);
995 	float offset = ceilf(frame.Height() / 2.0);
996 
997 	if (selectedFrame.left > frame.left) {
998 		StrokeLine(BPoint(frame.left, frame.bottom),
999 			BPoint(selectedFrame.left, frame.bottom));
1000 	}
1001 	if (selectedFrame.right + offset < Bounds().right) {
1002 		StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom),
1003 			BPoint(Bounds().right, frame.bottom));
1004 	}
1005 }
1006 
1007 
1008 //!	MouseDown, check if on tab, if so change tab if needed
1009 void
1010 TranslatorView::MouseDown(BPoint where)
1011 {
1012 	BRect frame = _TabFrame(fTabs.CountItems() - 1);
1013 	frame.left = 0;
1014 	if (!frame.Contains(where))
1015 		return;
1016 
1017 	for (int32 index = fTabs.CountItems(); index-- > 0;) {
1018 		if (!_TabFrame(index).Contains(where))
1019 			continue;
1020 
1021 		if (fActiveChild != index) {
1022 			// Hide current visible child
1023 			ChildAt(fActiveChild)->Hide();
1024 
1025 			// This loop is needed because it looks like in DataTranslations
1026 			// view gets hidden more than one time when user changes translator
1027 			while (ChildAt(index)->IsHidden()) {
1028 				ChildAt(index)->Show();
1029 			}
1030 
1031 			// Remember which one is currently visible
1032 			fActiveChild = index;
1033 			Invalidate(frame);
1034 			break;
1035 		}
1036 	}
1037 }
1038 
1039 
1040 //	#pragma mark -
1041 
1042 
1043 TranslatorWindow::TranslatorWindow(bool quitOnClose)
1044 	: BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW,
1045 		B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
1046 {
1047 	BRect extent(0, 0, 0, 0);
1048 	BView *config = NULL;
1049 	MakeConfig(NULL, &config, &extent);
1050 
1051 	AddChild(config);
1052 	ResizeTo(extent.Width(), extent.Height());
1053 
1054 	// Make application quit after this window close
1055 	if (quitOnClose)
1056 		SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE);
1057 }
1058 
1059 
1060 //	#pragma mark -
1061 
1062 
1063 //!	Hook to create and return our configuration view
1064 status_t
1065 MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
1066 {
1067 	*outView = new TranslatorView("TranslatorView");
1068 	*outExtent = (*outView)->Frame();
1069 	return B_OK;
1070 }
1071 
1072 
1073 //!	Determine whether or not we can handle this data
1074 status_t
1075 Identify(BPositionIO *inSource, const translation_format *inFormat, BMessage *ioExtension, translator_info *outInfo, uint32 outType)
1076 {
1077 	if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP) && outType != JP2_FORMAT)
1078 		return B_NO_TRANSLATOR;
1079 
1080 	// !!! You might need to make this buffer bigger to test for your native format
1081 	off_t position = inSource->Position();
1082 	uint8 header[sizeof(TranslatorBitmap)];
1083 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
1084 	inSource->Seek(position, SEEK_SET);
1085 	if (err < B_OK)
1086 		return err;
1087 
1088 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic) == B_TRANSLATOR_BITMAP) {
1089 		outInfo->type = inputFormats[1].type;
1090 		outInfo->translator = 0;
1091 		outInfo->group = inputFormats[1].group;
1092 		outInfo->quality = inputFormats[1].quality;
1093 		outInfo->capability = inputFormats[1].capability;
1094 		strcpy(outInfo->name, inputFormats[1].name);
1095 		strcpy(outInfo->MIME, inputFormats[1].MIME);
1096 	} else {
1097 		if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8) | header[7]) == JP2_BOX_JP) ||	// JP2
1098 			(header[0] == (JPC_MS_SOC >> 8) && header[1] == (JPC_MS_SOC & 0xff)))	// JPC
1099 		{
1100 			outInfo->type = inputFormats[0].type;
1101 			outInfo->translator = 0;
1102 			outInfo->group = inputFormats[0].group;
1103 			outInfo->quality = inputFormats[0].quality;
1104 			outInfo->capability = inputFormats[0].capability;
1105 			strcpy(outInfo->name, inputFormats[0].name);
1106 			strcpy(outInfo->MIME, inputFormats[0].MIME);
1107 			return B_OK;
1108 		} else
1109 			return B_NO_TRANSLATOR;
1110 	}
1111 
1112 	return B_OK;
1113 }
1114 
1115 
1116 //!	Arguably the most important method in the add-on
1117 status_t
1118 Translate(BPositionIO *inSource, const translator_info *inInfo, BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
1119 {
1120 	// If no specific type was requested, convert to the interchange format
1121 	if (outType == 0)
1122 		outType = B_TRANSLATOR_BITMAP;
1123 
1124 	// What action to take, based on the findings of Identify()
1125 	if (outType == inInfo->type)
1126 		return Copy(inSource, outDestination);
1127 	if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT)
1128 		return Compress(inSource, outDestination);
1129 	if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP)
1130 		return Decompress(inSource, outDestination);
1131 
1132 	return B_NO_TRANSLATOR;
1133 }
1134 
1135 
1136 //!	The user has requested the same format for input and output, so just copy
1137 status_t
1138 Copy(BPositionIO *in, BPositionIO *out)
1139 {
1140 	int block_size = 65536;
1141 	void *buffer = malloc(block_size);
1142 	char temp[1024];
1143 	if (buffer == NULL) {
1144 		buffer = temp;
1145 		block_size = 1024;
1146 	}
1147 	status_t err = B_OK;
1148 
1149 	// Read until end of file or error
1150 	while (1) {
1151 		ssize_t to_read = block_size;
1152 		err = in->Read(buffer, to_read);
1153 		// Explicit check for EOF
1154 		if (err == -1) {
1155 			if (buffer != temp)
1156 				free(buffer);
1157 			return B_OK;
1158 		}
1159 		if (err <= B_OK) break;
1160 		to_read = err;
1161 		err = out->Write(buffer, to_read);
1162 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
1163 		if (err < B_OK) break;
1164 	}
1165 
1166 	if (buffer != temp)
1167 		free(buffer);
1168 	return (err >= 0) ? B_OK : err;
1169 }
1170 
1171 
1172 //!	Encode into the native format
1173 status_t
1174 Compress(BPositionIO *in, BPositionIO *out)
1175 {
1176 	// Load settings
1177 	jpeg_settings settings;
1178 	LoadSettings(&settings);
1179 
1180 	// Read info about bitmap
1181 	TranslatorBitmap header;
1182 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
1183 	if (err < B_OK)
1184 		return err;
1185 	if (err < (int)sizeof(TranslatorBitmap))
1186 		return B_ERROR;
1187 
1188 	// Grab dimension, color space, and size information from the stream
1189 	BRect bounds;
1190 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
1191 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
1192 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
1193 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
1194 
1195 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
1196 
1197 	int width = bounds.IntegerWidth() + 1;
1198 	int height = bounds.IntegerHeight() + 1;
1199 
1200 	// Function pointer to write function
1201 	// It MUST point to proper function
1202 	void (*converter)(jas_matrix_t **pixels, jpr_uchar_t *inscanline, int width) = write_rgba32;
1203 
1204 	// Default color info
1205 	int out_color_space = JAS_IMAGE_CS_RGB;
1206 	int out_color_components = 3;
1207 
1208 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
1209 		case B_GRAY1:
1210 			if (settings.B_GRAY1_as_B_RGB24) {
1211 				converter = write_gray1_to_rgb24;
1212 			} else {
1213 				out_color_components = 1;
1214 				out_color_space = JAS_IMAGE_CS_GRAY;
1215 				converter = write_gray1_to_gray;
1216 			}
1217 			break;
1218 
1219 		case B_CMAP8:
1220 			converter = write_cmap8_to_rgb24;
1221 			break;
1222 
1223 		case B_GRAY8:
1224 			out_color_components = 1;
1225 			out_color_space = JAS_IMAGE_CS_GRAY;
1226 			converter = write_gray;
1227 			break;
1228 
1229 		case B_RGB15:
1230 		case B_RGBA15:
1231 			converter = write_rgb15_to_rgb24;
1232 			break;
1233 
1234 		case B_RGB15_BIG:
1235 		case B_RGBA15_BIG:
1236 			converter = write_rgb15b_to_rgb24;
1237 			break;
1238 
1239 		case B_RGB16:
1240 			converter = write_rgb16_to_rgb24;
1241 			break;
1242 
1243 		case B_RGB16_BIG:
1244 			converter = write_rgb16b_to_rgb24;
1245 			break;
1246 
1247 		case B_RGB24:
1248 			converter = write_rgb24;
1249 			break;
1250 
1251 		case B_RGB24_BIG:
1252 			converter = write_rgb24b;
1253 			break;
1254 
1255 		case B_RGB32:
1256 			converter = write_rgb32_to_rgb24;
1257 			break;
1258 
1259 		case B_RGB32_BIG:
1260 			converter = write_rgb32b_to_rgb24;
1261 			break;
1262 
1263 		case B_RGBA32:
1264 		/*
1265 			// In theory it should be possible to write 4 color components
1266 			// to jp2, so it should be possible to have transparency.
1267 			// Unfortunetly libjasper does not agree with that
1268 			// For now i don't know how to modify it :(
1269 
1270 			out_color_components = 4;
1271 			converter = write_rgba32;
1272 		*/
1273 			converter = write_rgb32_to_rgb24;
1274 			break;
1275 
1276 		case B_RGBA32_BIG:
1277 		/*
1278 			// In theory it should be possible to write 4 color components
1279 			// to jp2, so it should be possible to have transparency.
1280 			// Unfortunetly libjasper does not agree with that
1281 			// For now i don't know how to modify it :(
1282 
1283 			out_color_components = 4;
1284 			converter = write_rgba32b;
1285 		*/
1286 			converter = write_rgb32b_to_rgb24;
1287 			break;
1288 
1289 		default:
1290 			(new BAlert("Error", "Unknown color space.", "Quit"))->Go();
1291 			return B_ERROR;
1292 	}
1293 
1294 	jas_image_t *image;
1295 	jas_stream_t *outs;
1296 	jas_matrix_t *pixels[4];
1297 	jas_image_cmptparm_t component_info[4];
1298 
1299 	if (jas_init())
1300 		return B_ERROR;
1301 
1302 	if (!(outs = jas_stream_positionIOopen(out)))
1303 		return B_ERROR;
1304 
1305 	int32 i = 0;
1306 	for (i = 0; i < (long)out_color_components; i++) {
1307 		(void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t));
1308 		component_info[i].hstep = 1;
1309 		component_info[i].vstep = 1;
1310 		component_info[i].width = (unsigned int)width;
1311 		component_info[i].height = (unsigned int)height;
1312 		component_info[i].prec = (unsigned int)8;
1313 	}
1314 
1315 	image = jas_image_create((short)out_color_components, component_info, out_color_space);
1316 	if (image == (jas_image_t *)NULL)
1317 		return Error(outs, NULL, NULL, 0, NULL, B_ERROR);
1318 
1319 	jpr_uchar_t *in_scanline = (jpr_uchar_t*) malloc(in_row_bytes);
1320 	if (in_scanline == NULL)
1321 		return Error(outs, image, NULL, 0, NULL, B_ERROR);
1322 
1323 	for (i = 0; i < (long)out_color_components; i++) {
1324 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1325 		if (pixels[i] == (jas_matrix_t *)NULL)
1326 			return Error(outs, image, pixels, i+1, in_scanline, B_ERROR);
1327 	}
1328 
1329 	int32 y = 0;
1330 	for (y = 0; y < (long)height; y++) {
1331 		err = in->Read(in_scanline, in_row_bytes);
1332 		if (err < in_row_bytes)
1333 			return (err < B_OK) ? Error(outs, image, pixels, out_color_components, in_scanline, err) : Error(outs, image, pixels, out_color_components, in_scanline, B_ERROR);
1334 
1335 		converter(pixels, in_scanline, width);
1336 
1337 		for (i = 0; i < (long)out_color_components; i++)
1338 			(void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y, (unsigned int)width, 1, pixels[i]);
1339 	}
1340 
1341 	char opts[16];
1342 	sprintf(opts, "rate=%1f", (float)settings.Quality / 100.0);
1343 	if (jas_image_encode(image, outs, jas_image_strtofmt(settings.JPC ? (char*)"jpc" : (char*)"jp2"), opts))
1344 		return Error(outs, image, pixels, out_color_components, in_scanline, err);
1345 
1346 	free(in_scanline);
1347 
1348 	for (i = 0; i < (long)out_color_components; i++)
1349 		jas_matrix_destroy(pixels[i]);
1350 
1351 	jas_stream_close(outs);
1352 	jas_image_destroy(image);
1353 	jas_image_clearfmts();
1354 
1355 	return B_OK;
1356 }
1357 
1358 
1359 //!	Decode the native format
1360 status_t
1361 Decompress(BPositionIO *in, BPositionIO *out)
1362 {
1363 	jpeg_settings settings;
1364 	LoadSettings(&settings);
1365 
1366 	jas_image_t *image;
1367 	jas_stream_t *ins;
1368 	jas_matrix_t *pixels[4];
1369 
1370 	if (jas_init())
1371 		return B_ERROR;
1372 
1373 	if (!(ins = jas_stream_positionIOopen(in)))
1374 		return B_ERROR;
1375 
1376 	if (!(image = jas_image_decode(ins, -1, 0)))
1377 		return Error(ins, NULL, NULL, 0, NULL, B_ERROR);
1378 
1379 	// Default color info
1380 	color_space out_color_space;
1381 	int out_color_components;
1382 	int	in_color_components = jas_image_numcmpts(image);
1383 
1384 	// Function pointer to read function
1385 	// It MUST point to proper function
1386 	void (*converter)(jas_matrix_t **pixels, jpr_uchar_t *outscanline, int width) = NULL;
1387 
1388 	switch (jas_image_colorspace(image)) {
1389 		case JAS_IMAGE_CS_RGB:
1390 			out_color_components = 4;
1391 			if (in_color_components == 3) {
1392 				out_color_space = B_RGB32;
1393 				converter = read_rgb24_to_rgb32;
1394 			} else if (in_color_components == 4) {
1395 				out_color_space = B_RGBA32;
1396 				converter = read_rgba32;
1397 			} else {
1398 				(new BAlert("Error", "Other than RGB with 3 or 4 color components not implemented.", "Quit"))->Go();
1399 				return Error(ins, image, NULL, 0, NULL, B_ERROR);
1400 			}
1401 			break;
1402 		case JAS_IMAGE_CS_GRAY:
1403 			if (settings.B_GRAY8_as_B_RGB32) {
1404 				out_color_space = B_RGB32;
1405 				out_color_components = 4;
1406 				converter = read_gray_to_rgb32;
1407 			} else {
1408 				out_color_space = B_GRAY8;
1409 				out_color_components = 1;
1410 				converter = read_gray;
1411 			}
1412 			break;
1413 		case JAS_IMAGE_CS_YCBCR:
1414 			(new BAlert("Error", "color space YCBCR not implemented yet.", "Quit"))->Go();
1415 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1416 			break;
1417 		case JAS_IMAGE_CS_UNKNOWN:
1418 		default:
1419 			(new BAlert("Error", "color space unknown.", "Quit"))->Go();
1420 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1421 			break;
1422 	}
1423 
1424 	float width = (float)jas_image_width(image);
1425 	float height = (float)jas_image_height(image);
1426 
1427 	// Bytes count in one line of image (scanline)
1428 	int64 out_row_bytes = (int32)width * out_color_components;
1429 		// NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits
1430 
1431 	// !!! Initialize this bounds rect to the size of your image
1432 	BRect bounds(0, 0, width-1, height-1);
1433 
1434 	// Fill out the B_TRANSLATOR_BITMAP's header
1435 	TranslatorBitmap header;
1436 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
1437 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
1438 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
1439 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
1440 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
1441 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
1442 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes);
1443 	header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height));
1444 
1445 	// Write out the header
1446 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1447 	if (err < B_OK)
1448 		return Error(ins, image, NULL, 0, NULL, err);
1449 	if (err < (int)sizeof(TranslatorBitmap))
1450 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1451 
1452 	jpr_uchar_t *out_scanline = (jpr_uchar_t*) malloc(out_row_bytes);
1453 	if (out_scanline == NULL)
1454 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1455 
1456 	int32 i = 0;
1457 	for (i = 0; i < (long)in_color_components; i++) {
1458 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1459 		if (pixels[i] == (jas_matrix_t *)NULL)
1460 			return Error(ins, image, pixels, i+1, out_scanline, B_ERROR);
1461 	}
1462 
1463 	int32 y = 0;
1464 	for (y = 0; y < (long)height; y++) {
1465 		for (i = 0; i < (long)in_color_components; i++)
1466 			(void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y, (unsigned int)width, 1, pixels[i]);
1467 
1468 		converter(pixels, out_scanline, (int32)width);
1469 
1470 		err = out->Write(out_scanline, out_row_bytes);
1471 		if (err < out_row_bytes)
1472 			return (err < B_OK) ? Error(ins, image, pixels, in_color_components, out_scanline, err) : Error(ins, image, pixels, in_color_components, out_scanline, B_ERROR);
1473 	}
1474 
1475 	free(out_scanline);
1476 
1477 	for (i = 0; i < (long)in_color_components; i++)
1478 		jas_matrix_destroy(pixels[i]);
1479 
1480 	jas_stream_close(ins);
1481 	jas_image_destroy(image);
1482 	jas_image_clearfmts();
1483 
1484 	return B_OK;
1485 }
1486 
1487 
1488 /*!
1489 	Frees jpeg alocated memory
1490 	Returns given error (B_ERROR by default)
1491 */
1492 status_t
1493 Error(jas_stream_t *stream, jas_image_t *image, jas_matrix_t **pixels, int32 pixels_count, jpr_uchar_t *scanline, status_t error)
1494 {
1495 	if (pixels) {
1496 		int32 i;
1497 		for (i = 0; i < (long)pixels_count; i++) {
1498 			if (pixels[i] != NULL)
1499 				jas_matrix_destroy(pixels[i]);
1500 		}
1501 	}
1502 	if (stream)
1503 		jas_stream_close(stream);
1504 	if (image)
1505 		jas_image_destroy(image);
1506 
1507 	jas_image_clearfmts();
1508 	free(scanline);
1509 
1510 	return error;
1511 }
1512 
1513 
1514 //	#pragma mark -
1515 
1516 
1517 int
1518 main()
1519 {
1520 	BApplication app("application/x-vnd.Haiku-JPEG2000Translator");
1521 
1522 	TranslatorWindow *window = new TranslatorWindow();
1523 	window->Show();
1524 
1525 	app.Run();
1526 	return 0;
1527 }
1528 
1529