xref: /haiku/src/add-ons/translators/jpeg2000/JPEG2000Translator.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
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 		free(stream);
580 		return (jas_stream_t *)NULL;
581 	}
582 
583 	*((BPositionIO**)stream->obj_) = positionIO;
584 	stream->ops_ = (&positionIOops);
585 	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
586 	stream->bufbase_ = stream->tinybuf_;
587 	stream->bufsize_ = 1;
588 	stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
589 	stream->ptr_ = stream->bufstart_;
590 	stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
591 
592 	return stream;
593 }
594 
595 
596 //	#pragma mark - SView
597 
598 
599 SView::SView(const char *name, float x, float y)
600 	: BView(BRect(x, y, x, y), name, B_FOLLOW_NONE, B_WILL_DRAW)
601 {
602 	fPreferredWidth = 0;
603 	fPreferredHeight = 0;
604 
605 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
606 	SetLowColor(ViewColor());
607 
608 	SetFont(be_plain_font);
609 }
610 
611 
612 void
613 SView::GetPreferredSize(float* _width, float* _height)
614 {
615 	if (_width)
616 		*_width = fPreferredWidth;
617 	if (_height)
618 		*_height = fPreferredHeight;
619 }
620 
621 
622 void
623 SView::ResizeToPreferred()
624 {
625 	ResizeTo(fPreferredWidth, fPreferredHeight);
626 }
627 
628 
629 void
630 SView::ResizePreferredBy(float width, float height)
631 {
632 	fPreferredWidth += width;
633 	fPreferredHeight += height;
634 }
635 
636 
637 void
638 SView::AddChild(BView *child, BView *before)
639 {
640 	BView::AddChild(child, before);
641 	child->ResizeToPreferred();
642 	BRect frame = child->Frame();
643 
644 	if (frame.right > fPreferredWidth)
645 		fPreferredWidth = frame.right;
646 	if (frame.bottom > fPreferredHeight)
647 		fPreferredHeight = frame.bottom;
648 }
649 
650 
651 //	#pragma mark -
652 
653 
654 SSlider::SSlider(BRect frame, const char *name, const char *label,
655 		BMessage *message, int32 minValue, int32 maxValue, orientation posture,
656 		thumb_style thumbType, uint32 resizingMode, uint32 flags)
657 	: BSlider(frame, name, label, message, minValue, maxValue,
658 		posture, thumbType, resizingMode, flags)
659 {
660 	rgb_color barColor = { 0, 0, 229, 255 };
661 	UseFillColor(true, &barColor);
662 }
663 
664 
665 //!	Update status string - show actual value
666 char*
667 SSlider::UpdateText() const
668 {
669 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%ld", Value());
670 	return fStatusLabel;
671 }
672 
673 
674 //!	BSlider::ResizeToPreferred + Resize width if it's too small to show label
675 // and status
676 void
677 SSlider::ResizeToPreferred()
678 {
679 	int32 width = (int32)ceil(StringWidth(Label()) + StringWidth("9999"));
680 	if (width < 230)
681 		width = 230;
682 
683 	float w, h;
684 	GetPreferredSize(&w, &h);
685 	ResizeTo(width, h);
686 }
687 
688 
689 //	#pragma mark -
690 
691 
692 TranslatorReadView::TranslatorReadView(const char *name, jpeg_settings *settings,
693 		float x, float y)
694 	: SView(name, x, y),
695 	fSettings(settings)
696 {
697 	fGrayAsRGB32 = new BCheckBox(BRect(10, GetPreferredHeight(), 10,
698 		GetPreferredHeight()), "grayasrgb32", VIEW_LABEL_GRAYASRGB32,
699 		new BMessage(VIEW_MSG_SET_GRAYASRGB32));
700 	fGrayAsRGB32->SetFont(be_plain_font);
701 	if (fSettings->B_GRAY8_as_B_RGB32)
702 		fGrayAsRGB32->SetValue(1);
703 
704 	AddChild(fGrayAsRGB32);
705 
706 	ResizeToPreferred();
707 }
708 
709 
710 void
711 TranslatorReadView::AttachedToWindow()
712 {
713 	fGrayAsRGB32->SetTarget(this);
714 }
715 
716 
717 void
718 TranslatorReadView::MessageReceived(BMessage *message)
719 {
720 	switch (message->what) {
721 		case VIEW_MSG_SET_GRAYASRGB32:
722 		{
723 			int32 value;
724 			if (message->FindInt32("be:value", &value) == B_OK) {
725 				fSettings->B_GRAY8_as_B_RGB32 = value;
726 				SaveSettings(fSettings);
727 			}
728 			break;
729 		}
730 		default:
731 			BView::MessageReceived(message);
732 			break;
733 	}
734 }
735 
736 
737 //	#pragma mark - TranslatorWriteView
738 
739 
740 TranslatorWriteView::TranslatorWriteView(const char *name, jpeg_settings *settings,
741 		float x, float y)
742 	: SView(name, x, y),
743 	fSettings(settings)
744 {
745 	fQualitySlider = new SSlider(BRect(10, GetPreferredHeight(), 10,
746 		GetPreferredHeight()), "quality", VIEW_LABEL_QUALITY,
747 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
748 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
749 	fQualitySlider->SetHashMarkCount(10);
750 	fQualitySlider->SetLimitLabels("Low", "High");
751 	fQualitySlider->SetFont(be_plain_font);
752 	fQualitySlider->SetValue(fSettings->Quality);
753 	AddChild(fQualitySlider);
754 
755 	fGrayAsRGB24 = new BCheckBox(BRect(10, GetPreferredHeight() + 5, 25,
756 		GetPreferredHeight() + 5), "gray1asrgb24", VIEW_LABEL_GRAY1ASRGB24,
757 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
758 	fGrayAsRGB24->SetFont(be_plain_font);
759 	if (fSettings->B_GRAY1_as_B_RGB24)
760 		fGrayAsRGB24->SetValue(1);
761 
762 	AddChild(fGrayAsRGB24);
763 
764 	fCodeStreamOnly = new BCheckBox(BRect(10, GetPreferredHeight() + 5, 10,
765 		GetPreferredHeight()), "codestreamonly", VIEW_LABEL_JPC,
766 		new BMessage(VIEW_MSG_SET_JPC));
767 	fCodeStreamOnly->SetFont(be_plain_font);
768 	if (fSettings->JPC)
769 		fCodeStreamOnly->SetValue(1);
770 
771 	AddChild(fCodeStreamOnly);
772 
773 	ResizeToPreferred();
774 }
775 
776 
777 void
778 TranslatorWriteView::AttachedToWindow()
779 {
780 	fQualitySlider->SetTarget(this);
781 	fGrayAsRGB24->SetTarget(this);
782 	fCodeStreamOnly->SetTarget(this);
783 }
784 
785 
786 void
787 TranslatorWriteView::MessageReceived(BMessage *message)
788 {
789 	switch (message->what) {
790 		case VIEW_MSG_SET_QUALITY:
791 		{
792 			int32 value;
793 			if (message->FindInt32("be:value", &value) == B_OK) {
794 				fSettings->Quality = value;
795 				SaveSettings(fSettings);
796 			}
797 			break;
798 		}
799 		case VIEW_MSG_SET_GRAY1ASRGB24:
800 		{
801 			int32 value;
802 			if (message->FindInt32("be:value", &value) == B_OK) {
803 				fSettings->B_GRAY1_as_B_RGB24 = value;
804 				SaveSettings(fSettings);
805 			}
806 			break;
807 		}
808 		case VIEW_MSG_SET_JPC:
809 		{
810 			int32 value;
811 			if (message->FindInt32("be:value", &value) == B_OK) {
812 				fSettings->JPC = value;
813 				SaveSettings(fSettings);
814 			}
815 			break;
816 		}
817 		default:
818 			BView::MessageReceived(message);
819 			break;
820 	}
821 }
822 
823 
824 //	#pragma mark -
825 
826 
827 TranslatorAboutView::TranslatorAboutView(const char *name, float x, float y)
828 	: SView(name, x, y)
829 {
830 	BStringView *title = new BStringView(BRect(10, 0, 10, 0), "Title",
831 		translatorName);
832 	title->SetFont(be_bold_font);
833 
834 	AddChild(title);
835 
836 	BRect rect = title->Bounds();
837 	float space = title->StringWidth("    ");
838 
839 	char versionString[16];
840 	sprintf(versionString, "v%d.%d.%d", (int)(translatorVersion >> 8),
841 		(int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf));
842 
843 	BStringView *version = new BStringView(BRect(rect.right+space, rect.top,
844 		rect.right+space, rect.top), "Version", versionString);
845 	version->SetFont(be_plain_font);
846 	version->SetFontSize(9);
847 	// Make version be in the same line as title
848 	version->ResizeToPreferred();
849 	version->MoveBy(0, rect.bottom-version->Frame().bottom);
850 
851 	AddChild(version);
852 
853 	// Now for each line in translatorInfo add a BStringView
854 	char* current = translatorInfo;
855 	int32 index = 1;
856 	while (current != NULL && current[0]) {
857 		char text[128];
858 		char* newLine = strchr(current, '\n');
859 		if (newLine == NULL) {
860 			strlcpy(text, current, sizeof(text));
861 			current = NULL;
862 		} else {
863 			strlcpy(text, current, min_c((int32)sizeof(text),
864 				newLine + 1 - current));
865 			current = newLine + 1;
866 		}
867 
868 		BStringView* string = new BStringView(BRect(10, GetPreferredHeight(),
869 			10, GetPreferredHeight()), "copyright", text);
870 		if (index > 3)
871 			string->SetFontSize(9);
872 		AddChild(string);
873 
874 		index++;
875 	}
876 
877 	ResizeToPreferred();
878 }
879 
880 
881 //	#pragma mark -
882 
883 
884 TranslatorView::TranslatorView(const char *name)
885 	: SView(name),
886 	fTabWidth(30),
887 	fActiveChild(0)
888 {
889 	// Set global var to true
890 	gAreSettingsRunning = true;
891 
892 	// Load settings to global settings struct
893 	LoadSettings(&fSettings);
894 
895 	font_height fontHeight;
896 	GetFontHeight(&fontHeight);
897 	fTabHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent
898 		+ fontHeight.leading) + 7;
899 	// Add left and top margins
900 	float top = fTabHeight + 20;
901 	float left = 0;
902 
903 	// This will remember longest string width
904 	int32 nameWidth = 0;
905 
906 	SView *view = new TranslatorWriteView("Write", &fSettings, left, top);
907 	AddChild(view);
908 	nameWidth = (int32)StringWidth(view->Name());
909 	fTabs.AddItem(new BTab(view));
910 
911 	view = new TranslatorReadView("Read", &fSettings, left, top);
912 	AddChild(view);
913 	if (nameWidth < StringWidth(view->Name()))
914 		nameWidth = (int32)StringWidth(view->Name());
915 	fTabs.AddItem(new BTab(view));
916 
917 	view = new TranslatorAboutView("About", left, top);
918 	AddChild(view);
919 	if (nameWidth < StringWidth(view->Name()))
920 		nameWidth = (int32)StringWidth(view->Name());
921 	fTabs.AddItem(new BTab(view));
922 
923 	fTabWidth += nameWidth;
924 	if (fTabWidth * CountChildren() > GetPreferredWidth())
925 		ResizePreferredBy((fTabWidth * CountChildren()) - GetPreferredWidth(), 0);
926 
927 	// Add right and bottom margins
928 	ResizePreferredBy(10, 15);
929 
930 	ResizeToPreferred();
931 
932 	// Make TranslatorView resize itself with parent
933 	SetFlags(Flags() | B_FOLLOW_ALL);
934 }
935 
936 
937 TranslatorView::~TranslatorView()
938 {
939 	gAreSettingsRunning = false;
940 
941 	BTab* tab;
942 	while ((tab = (BTab*)fTabs.RemoveItem((int32)0)) != NULL) {
943 		delete tab;
944 	}
945 }
946 
947 
948 //!	Attached to window - resize parent to preferred
949 void
950 TranslatorView::AttachedToWindow()
951 {
952 	// Hide all children except first one
953 	BView *child;
954 	int32 index = 1;
955 	while ((child = ChildAt(index++)) != NULL)
956 		child->Hide();
957 
958 }
959 
960 
961 BRect
962 TranslatorView::_TabFrame(int32 index) const
963 {
964 	return BRect(index * fTabWidth, 10, (index + 1) * fTabWidth, 10 + fTabHeight);
965 }
966 
967 
968 void
969 TranslatorView::Draw(BRect updateRect)
970 {
971 	// This is needed because DataTranslations app hides children
972 	// after user changes translator
973 	if (ChildAt(fActiveChild)->IsHidden())
974 		ChildAt(fActiveChild)->Show();
975 
976 	// Clear
977 	SetHighColor(ViewColor());
978 	BRect frame = _TabFrame(0);
979 	FillRect(BRect(frame.left, frame.top, Bounds().right, frame.bottom - 1));
980 
981 	int32 index = 0;
982 	BTab* tab;
983 	while ((tab = (BTab*)fTabs.ItemAt(index)) != NULL) {
984 		tab_position position;
985 		if (fActiveChild == index)
986 			position = B_TAB_FRONT;
987 		else if (index == 0)
988 			position = B_TAB_FIRST;
989 		else
990 			position = B_TAB_ANY;
991 
992 		tab->DrawTab(this, _TabFrame(index), position, index + 1 != fActiveChild);
993 		index++;
994 	}
995 
996 	// Draw bottom edge
997 	SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT));
998 
999 	BRect selectedFrame = _TabFrame(fActiveChild);
1000 	float offset = ceilf(frame.Height() / 2.0);
1001 
1002 	if (selectedFrame.left > frame.left) {
1003 		StrokeLine(BPoint(frame.left, frame.bottom),
1004 			BPoint(selectedFrame.left, frame.bottom));
1005 	}
1006 	if (selectedFrame.right + offset < Bounds().right) {
1007 		StrokeLine(BPoint(selectedFrame.right + offset, frame.bottom),
1008 			BPoint(Bounds().right, frame.bottom));
1009 	}
1010 }
1011 
1012 
1013 //!	MouseDown, check if on tab, if so change tab if needed
1014 void
1015 TranslatorView::MouseDown(BPoint where)
1016 {
1017 	BRect frame = _TabFrame(fTabs.CountItems() - 1);
1018 	frame.left = 0;
1019 	if (!frame.Contains(where))
1020 		return;
1021 
1022 	for (int32 index = fTabs.CountItems(); index-- > 0;) {
1023 		if (!_TabFrame(index).Contains(where))
1024 			continue;
1025 
1026 		if (fActiveChild != index) {
1027 			// Hide current visible child
1028 			ChildAt(fActiveChild)->Hide();
1029 
1030 			// This loop is needed because it looks like in DataTranslations
1031 			// view gets hidden more than one time when user changes translator
1032 			while (ChildAt(index)->IsHidden()) {
1033 				ChildAt(index)->Show();
1034 			}
1035 
1036 			// Remember which one is currently visible
1037 			fActiveChild = index;
1038 			Invalidate(frame);
1039 			break;
1040 		}
1041 	}
1042 }
1043 
1044 
1045 //	#pragma mark -
1046 
1047 
1048 TranslatorWindow::TranslatorWindow(bool quitOnClose)
1049 	: BWindow(BRect(100, 100, 100, 100), "JPEG Settings", B_TITLED_WINDOW,
1050 		B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
1051 {
1052 	BRect extent(0, 0, 0, 0);
1053 	BView *config = NULL;
1054 	MakeConfig(NULL, &config, &extent);
1055 
1056 	AddChild(config);
1057 	ResizeTo(extent.Width(), extent.Height());
1058 
1059 	// Make application quit after this window close
1060 	if (quitOnClose)
1061 		SetFlags(Flags() | B_QUIT_ON_WINDOW_CLOSE);
1062 }
1063 
1064 
1065 //	#pragma mark -
1066 
1067 
1068 //!	Hook to create and return our configuration view
1069 status_t
1070 MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
1071 {
1072 	*outView = new TranslatorView("TranslatorView");
1073 	*outExtent = (*outView)->Frame();
1074 	return B_OK;
1075 }
1076 
1077 
1078 //!	Determine whether or not we can handle this data
1079 status_t
1080 Identify(BPositionIO *inSource, const translation_format *inFormat,
1081 	BMessage *ioExtension, translator_info *outInfo, uint32 outType)
1082 {
1083 	if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP)
1084 		&& outType != JP2_FORMAT)
1085 		return B_NO_TRANSLATOR;
1086 
1087 	// !!! You might need to make this buffer bigger to test for your
1088 	// native format
1089 	off_t position = inSource->Position();
1090 	uint8 header[sizeof(TranslatorBitmap)];
1091 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
1092 	inSource->Seek(position, SEEK_SET);
1093 	if (err < B_OK)
1094 		return err;
1095 
1096 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic)
1097 		== B_TRANSLATOR_BITMAP) {
1098 		outInfo->type = inputFormats[1].type;
1099 		outInfo->translator = 0;
1100 		outInfo->group = inputFormats[1].group;
1101 		outInfo->quality = inputFormats[1].quality;
1102 		outInfo->capability = inputFormats[1].capability;
1103 		strcpy(outInfo->name, inputFormats[1].name);
1104 		strcpy(outInfo->MIME, inputFormats[1].MIME);
1105 	} else {
1106 		if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8)
1107 			| header[7]) == JP2_BOX_JP) // JP2
1108 			|| (header[0] == (JPC_MS_SOC >> 8) && header[1]
1109 			== (JPC_MS_SOC & 0xff)))	// JPC
1110 		{
1111 			outInfo->type = inputFormats[0].type;
1112 			outInfo->translator = 0;
1113 			outInfo->group = inputFormats[0].group;
1114 			outInfo->quality = inputFormats[0].quality;
1115 			outInfo->capability = inputFormats[0].capability;
1116 			strcpy(outInfo->name, inputFormats[0].name);
1117 			strcpy(outInfo->MIME, inputFormats[0].MIME);
1118 			return B_OK;
1119 		} else
1120 			return B_NO_TRANSLATOR;
1121 	}
1122 
1123 	return B_OK;
1124 }
1125 
1126 
1127 //!	Arguably the most important method in the add-on
1128 status_t
1129 Translate(BPositionIO *inSource, const translator_info *inInfo,
1130 	BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
1131 {
1132 	// If no specific type was requested, convert to the interchange format
1133 	if (outType == 0)
1134 		outType = B_TRANSLATOR_BITMAP;
1135 
1136 	// What action to take, based on the findings of Identify()
1137 	if (outType == inInfo->type)
1138 		return Copy(inSource, outDestination);
1139 	if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT)
1140 		return Compress(inSource, outDestination);
1141 	if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP)
1142 		return Decompress(inSource, outDestination);
1143 
1144 	return B_NO_TRANSLATOR;
1145 }
1146 
1147 
1148 //!	The user has requested the same format for input and output, so just copy
1149 status_t
1150 Copy(BPositionIO *in, BPositionIO *out)
1151 {
1152 	int block_size = 65536;
1153 	void *buffer = malloc(block_size);
1154 	char temp[1024];
1155 	if (buffer == NULL) {
1156 		buffer = temp;
1157 		block_size = 1024;
1158 	}
1159 	status_t err = B_OK;
1160 
1161 	// Read until end of file or error
1162 	while (1) {
1163 		ssize_t to_read = block_size;
1164 		err = in->Read(buffer, to_read);
1165 		// Explicit check for EOF
1166 		if (err == -1) {
1167 			if (buffer != temp)
1168 				free(buffer);
1169 			return B_OK;
1170 		}
1171 		if (err <= B_OK) break;
1172 		to_read = err;
1173 		err = out->Write(buffer, to_read);
1174 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
1175 		if (err < B_OK) break;
1176 	}
1177 
1178 	if (buffer != temp)
1179 		free(buffer);
1180 	return (err >= 0) ? B_OK : err;
1181 }
1182 
1183 
1184 //!	Encode into the native format
1185 status_t
1186 Compress(BPositionIO *in, BPositionIO *out)
1187 {
1188 	// Load settings
1189 	jpeg_settings settings;
1190 	LoadSettings(&settings);
1191 
1192 	// Read info about bitmap
1193 	TranslatorBitmap header;
1194 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
1195 	if (err < B_OK)
1196 		return err;
1197 	if (err < (int)sizeof(TranslatorBitmap))
1198 		return B_ERROR;
1199 
1200 	// Grab dimension, color space, and size information from the stream
1201 	BRect bounds;
1202 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
1203 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
1204 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
1205 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
1206 
1207 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
1208 
1209 	int width = bounds.IntegerWidth() + 1;
1210 	int height = bounds.IntegerHeight() + 1;
1211 
1212 	// Function pointer to write function
1213 	// It MUST point to proper function
1214 	void (*converter)(jas_matrix_t **pixels, jpr_uchar_t *inscanline,
1215 		int width) = write_rgba32;
1216 
1217 	// Default color info
1218 	int out_color_space = JAS_IMAGE_CS_RGB;
1219 	int out_color_components = 3;
1220 
1221 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
1222 		case B_GRAY1:
1223 			if (settings.B_GRAY1_as_B_RGB24) {
1224 				converter = write_gray1_to_rgb24;
1225 			} else {
1226 				out_color_components = 1;
1227 				out_color_space = JAS_IMAGE_CS_GRAY;
1228 				converter = write_gray1_to_gray;
1229 			}
1230 			break;
1231 
1232 		case B_CMAP8:
1233 			converter = write_cmap8_to_rgb24;
1234 			break;
1235 
1236 		case B_GRAY8:
1237 			out_color_components = 1;
1238 			out_color_space = JAS_IMAGE_CS_GRAY;
1239 			converter = write_gray;
1240 			break;
1241 
1242 		case B_RGB15:
1243 		case B_RGBA15:
1244 			converter = write_rgb15_to_rgb24;
1245 			break;
1246 
1247 		case B_RGB15_BIG:
1248 		case B_RGBA15_BIG:
1249 			converter = write_rgb15b_to_rgb24;
1250 			break;
1251 
1252 		case B_RGB16:
1253 			converter = write_rgb16_to_rgb24;
1254 			break;
1255 
1256 		case B_RGB16_BIG:
1257 			converter = write_rgb16b_to_rgb24;
1258 			break;
1259 
1260 		case B_RGB24:
1261 			converter = write_rgb24;
1262 			break;
1263 
1264 		case B_RGB24_BIG:
1265 			converter = write_rgb24b;
1266 			break;
1267 
1268 		case B_RGB32:
1269 			converter = write_rgb32_to_rgb24;
1270 			break;
1271 
1272 		case B_RGB32_BIG:
1273 			converter = write_rgb32b_to_rgb24;
1274 			break;
1275 
1276 		case B_RGBA32:
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_rgba32;
1285 		*/
1286 			converter = write_rgb32_to_rgb24;
1287 			break;
1288 
1289 		case B_RGBA32_BIG:
1290 		/*
1291 			// In theory it should be possible to write 4 color components
1292 			// to jp2, so it should be possible to have transparency.
1293 			// Unfortunetly libjasper does not agree with that
1294 			// For now i don't know how to modify it :(
1295 
1296 			out_color_components = 4;
1297 			converter = write_rgba32b;
1298 		*/
1299 			converter = write_rgb32b_to_rgb24;
1300 			break;
1301 
1302 		default:
1303 			(new BAlert("Error", "Unknown color space.", "Quit"))->Go();
1304 			return B_ERROR;
1305 	}
1306 
1307 	jas_image_t *image;
1308 	jas_stream_t *outs;
1309 	jas_matrix_t *pixels[4];
1310 	jas_image_cmptparm_t component_info[4];
1311 
1312 	if (jas_init())
1313 		return B_ERROR;
1314 
1315 	if (!(outs = jas_stream_positionIOopen(out)))
1316 		return B_ERROR;
1317 
1318 	int32 i = 0;
1319 	for (i = 0; i < (long)out_color_components; i++) {
1320 		(void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t));
1321 		component_info[i].hstep = 1;
1322 		component_info[i].vstep = 1;
1323 		component_info[i].width = (unsigned int)width;
1324 		component_info[i].height = (unsigned int)height;
1325 		component_info[i].prec = (unsigned int)8;
1326 	}
1327 
1328 	image = jas_image_create((short)out_color_components, component_info,
1329 		out_color_space);
1330 	if (image == (jas_image_t *)NULL)
1331 		return Error(outs, NULL, NULL, 0, NULL, B_ERROR);
1332 
1333 	jpr_uchar_t *in_scanline = (jpr_uchar_t*) malloc(in_row_bytes);
1334 	if (in_scanline == NULL)
1335 		return Error(outs, image, NULL, 0, NULL, B_ERROR);
1336 
1337 	for (i = 0; i < (long)out_color_components; i++) {
1338 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1339 		if (pixels[i] == (jas_matrix_t *)NULL)
1340 			return Error(outs, image, pixels, i+1, in_scanline, B_ERROR);
1341 	}
1342 
1343 	int32 y = 0;
1344 	for (y = 0; y < (long)height; y++) {
1345 		err = in->Read(in_scanline, in_row_bytes);
1346 		if (err < in_row_bytes) {
1347 			return (err < B_OK) ?
1348 				Error(outs, image, pixels, out_color_components, in_scanline,
1349 					err)
1350 				: Error(outs, image, pixels, out_color_components, in_scanline,
1351 					B_ERROR);
1352 		}
1353 
1354 		converter(pixels, in_scanline, width);
1355 
1356 		for (i = 0; i < (long)out_color_components; i++) {
1357 			(void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y,
1358 				(unsigned int)width, 1, pixels[i]);
1359 		}
1360 	}
1361 
1362 	char opts[16];
1363 	sprintf(opts, "rate=%1f", (float)settings.Quality / 100.0);
1364 	if (jas_image_encode(image, outs, jas_image_strtofmt(settings.JPC ?
1365 		(char*)"jpc" : (char*)"jp2"), opts)) {
1366 		return Error(outs, image, pixels, out_color_components, in_scanline, err);
1367 	}
1368 
1369 	free(in_scanline);
1370 
1371 	for (i = 0; i < (long)out_color_components; i++)
1372 		jas_matrix_destroy(pixels[i]);
1373 
1374 	jas_stream_close(outs);
1375 	jas_image_destroy(image);
1376 	jas_image_clearfmts();
1377 
1378 	return B_OK;
1379 }
1380 
1381 
1382 //!	Decode the native format
1383 status_t
1384 Decompress(BPositionIO *in, BPositionIO *out)
1385 {
1386 	jpeg_settings settings;
1387 	LoadSettings(&settings);
1388 
1389 	jas_image_t *image;
1390 	jas_stream_t *ins;
1391 	jas_matrix_t *pixels[4];
1392 
1393 	if (jas_init())
1394 		return B_ERROR;
1395 
1396 	if (!(ins = jas_stream_positionIOopen(in)))
1397 		return B_ERROR;
1398 
1399 	if (!(image = jas_image_decode(ins, -1, 0)))
1400 		return Error(ins, NULL, NULL, 0, NULL, B_ERROR);
1401 
1402 	// Default color info
1403 	color_space out_color_space;
1404 	int out_color_components;
1405 	int	in_color_components = jas_image_numcmpts(image);
1406 
1407 	// Function pointer to read function
1408 	// It MUST point to proper function
1409 	void (*converter)(jas_matrix_t **pixels, jpr_uchar_t *outscanline,
1410 		int width) = NULL;
1411 
1412 	switch (jas_image_colorspace(image)) {
1413 		case JAS_IMAGE_CS_RGB:
1414 			out_color_components = 4;
1415 			if (in_color_components == 3) {
1416 				out_color_space = B_RGB32;
1417 				converter = read_rgb24_to_rgb32;
1418 			} else if (in_color_components == 4) {
1419 				out_color_space = B_RGBA32;
1420 				converter = read_rgba32;
1421 			} else {
1422 				(new BAlert("Error", "Other than RGB with 3 or 4 color "
1423 					"components not implemented.", "Quit"))->Go();
1424 				return Error(ins, image, NULL, 0, NULL, B_ERROR);
1425 			}
1426 			break;
1427 		case JAS_IMAGE_CS_GRAY:
1428 			if (settings.B_GRAY8_as_B_RGB32) {
1429 				out_color_space = B_RGB32;
1430 				out_color_components = 4;
1431 				converter = read_gray_to_rgb32;
1432 			} else {
1433 				out_color_space = B_GRAY8;
1434 				out_color_components = 1;
1435 				converter = read_gray;
1436 			}
1437 			break;
1438 		case JAS_IMAGE_CS_YCBCR:
1439 			(new BAlert("Error", "color space YCBCR not implemented yet.",
1440 				"Quit"))->Go();
1441 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1442 			break;
1443 		case JAS_IMAGE_CS_UNKNOWN:
1444 		default:
1445 			(new BAlert("Error", "color space unknown.", "Quit"))->Go();
1446 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1447 			break;
1448 	}
1449 
1450 	float width = (float)jas_image_width(image);
1451 	float height = (float)jas_image_height(image);
1452 
1453 	// Bytes count in one line of image (scanline)
1454 	int64 out_row_bytes = (int32)width * out_color_components;
1455 		// NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits
1456 
1457 	// !!! Initialize this bounds rect to the size of your image
1458 	BRect bounds(0, 0, width-1, height-1);
1459 
1460 	// Fill out the B_TRANSLATOR_BITMAP's header
1461 	TranslatorBitmap header;
1462 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
1463 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
1464 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
1465 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
1466 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
1467 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
1468 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes);
1469 	header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height));
1470 
1471 	// Write out the header
1472 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1473 	if (err < B_OK)
1474 		return Error(ins, image, NULL, 0, NULL, err);
1475 	if (err < (int)sizeof(TranslatorBitmap))
1476 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1477 
1478 	jpr_uchar_t *out_scanline = (jpr_uchar_t*) malloc(out_row_bytes);
1479 	if (out_scanline == NULL)
1480 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1481 
1482 	int32 i = 0;
1483 	for (i = 0; i < (long)in_color_components; i++) {
1484 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1485 		if (pixels[i] == (jas_matrix_t *)NULL)
1486 			return Error(ins, image, pixels, i+1, out_scanline, B_ERROR);
1487 	}
1488 
1489 	int32 y = 0;
1490 	for (y = 0; y < (long)height; y++) {
1491 		for (i = 0; i < (long)in_color_components; i++) {
1492 			(void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y,
1493 				(unsigned int)width, 1, pixels[i]);
1494 		}
1495 
1496 		converter(pixels, out_scanline, (int32)width);
1497 
1498 		err = out->Write(out_scanline, out_row_bytes);
1499 		if (err < out_row_bytes) {
1500 			return (err < B_OK) ?
1501 				Error(ins, image, pixels, in_color_components, out_scanline,
1502 					err)
1503 				: Error(ins, image, pixels, in_color_components, out_scanline,
1504 					B_ERROR);
1505 		}
1506 	}
1507 
1508 	free(out_scanline);
1509 
1510 	for (i = 0; i < (long)in_color_components; i++)
1511 		jas_matrix_destroy(pixels[i]);
1512 
1513 	jas_stream_close(ins);
1514 	jas_image_destroy(image);
1515 	jas_image_clearfmts();
1516 
1517 	return B_OK;
1518 }
1519 
1520 
1521 /*!
1522 	Frees jpeg alocated memory
1523 	Returns given error (B_ERROR by default)
1524 */
1525 status_t
1526 Error(jas_stream_t *stream, jas_image_t *image, jas_matrix_t **pixels,
1527 	int32 pixels_count, jpr_uchar_t *scanline, status_t error)
1528 {
1529 	if (pixels) {
1530 		int32 i;
1531 		for (i = 0; i < (long)pixels_count; i++) {
1532 			if (pixels[i] != NULL)
1533 				jas_matrix_destroy(pixels[i]);
1534 		}
1535 	}
1536 	if (stream)
1537 		jas_stream_close(stream);
1538 	if (image)
1539 		jas_image_destroy(image);
1540 
1541 	jas_image_clearfmts();
1542 	free(scanline);
1543 
1544 	return error;
1545 }
1546 
1547 
1548 //	#pragma mark -
1549 
1550 
1551 int
1552 main()
1553 {
1554 	BApplication app("application/x-vnd.Haiku-JPEG2000Translator");
1555 
1556 	TranslatorWindow *window = new TranslatorWindow();
1557 	window->Show();
1558 
1559 	app.Run();
1560 	return 0;
1561 }
1562 
1563