xref: /haiku/src/add-ons/translators/jpeg2000/JPEG2000Translator.cpp (revision 5fae0bc1a2f74ccf56b7e3958149317d6af2cccc)
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 "TranslatorWindow.h"
35 
36 #include <syslog.h>
37 
38 #include <LayoutBuilder.h>
39 #include <TabView.h>
40 #include <TextView.h>
41 
42 
43 #undef B_TRANSLATION_CONTEXT
44 #define B_TRANSLATION_CONTEXT "JPEG2000Translator"
45 
46 // Set these accordingly
47 #define JP2_ACRONYM "JP2"
48 #define JP2_FORMAT 'JP2 '
49 #define JP2_MIME_STRING "image/jp2"
50 #define JP2_DESCRIPTION "JPEG2000 image"
51 
52 // The translation kit's native file type
53 #define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
54 #define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEG2000Translator)"
55 
56 static int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 0, 0);
57 
58 static const char* sTranslatorName = B_TRANSLATE("JPEG2000 images");
59 static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Shard\n"
60 	"©2005-2006, Haiku\n"
61 	"\n"
62 	"Based on JasPer library:\n"
63 	"© 1999-2000, Image Power, Inc. and\n"
64 	"the University of British Columbia, Canada.\n"
65 	"© 2001-2003 Michael David Adams.\n"
66 	"\thttp://www.ece.uvic.ca/~mdadams/jasper/\n"
67 	"\n"
68 	"ImageMagick's jp2 codec was used as \"tutorial\".\n"
69 	"\thttp://www.imagemagick.org/\n");
70 
71 static const translation_format sInputFormats[] = {
72 	{ JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
73 		JP2_MIME_STRING, JP2_DESCRIPTION },
74 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
75 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
76 };
77 
78 static const translation_format sOutputFormats[] = {
79 	{ JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
80 		JP2_MIME_STRING, JP2_DESCRIPTION },
81 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
82 		B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
83 };
84 
85 
86 static const TranSetting sDefaultSettings[] = {
87 	{JP2_SET_QUALITY, TRAN_SETTING_INT32, 25},
88 	{JP2_SET_JPC, TRAN_SETTING_BOOL, false},
89 	{JP2_SET_GRAY1_AS_B_RGB24, TRAN_SETTING_BOOL, false},
90 	{JP2_SET_GRAY8_AS_B_RGB32, TRAN_SETTING_BOOL, true}
91 };
92 
93 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
94 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
95 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
96 
97 
98 #define	JP2_BOX_JP		0x6a502020
99 #define	JPC_MS_SOC		0xff4f
100 
101 
102 namespace conversion{
103 //!	Make RGB32 scanline from *pixels[3]
104 inline void
105 read_rgb24_to_rgb32(jas_matrix_t** pixels, uchar* scanline, int width)
106 {
107 	int32 index = 0;
108 	int32 x = 0;
109 	while (x < width) {
110 		scanline[index++] = (uchar)jas_matrix_getv(pixels[2], x);
111 		scanline[index++] = (uchar)jas_matrix_getv(pixels[1], x);
112 		scanline[index++] = (uchar)jas_matrix_getv(pixels[0], x);
113 		scanline[index++] = 255;
114 		x++;
115 	}
116 }
117 
118 
119 //!	Make gray scanline from *pixels[1]
120 inline void
121 read_gray_to_rgb32(jas_matrix_t** pixels, uchar* scanline, int width)
122 {
123 	int32 index = 0;
124 	int32 x = 0;
125 	uchar color = 0;
126 	while (x < width) {
127 		color = (uchar)jas_matrix_getv(pixels[0], x++);
128 		scanline[index++] = color;
129 		scanline[index++] = color;
130 		scanline[index++] = color;
131 		scanline[index++] = 255;
132 	}
133 }
134 
135 
136 /*!
137 	Make RGBA32 scanline from *pixels[4]
138 	(just read data to scanline)
139 */
140 inline void
141 read_rgba32(jas_matrix_t** pixels, uchar *scanline, int width)
142 {
143 	int32 index = 0;
144 	int32 x = 0;
145 	while (x < width) {
146 		scanline[index++] = (uchar)jas_matrix_getv(pixels[2], x);
147 		scanline[index++] = (uchar)jas_matrix_getv(pixels[1], x);
148 		scanline[index++] = (uchar)jas_matrix_getv(pixels[0], x);
149 		scanline[index++] = (uchar)jas_matrix_getv(pixels[3], x);
150 		x++;
151 	}
152 }
153 
154 
155 /*!
156 	Make gray scanline from *pixels[1]
157 	(just read data to scanline)
158 */
159 inline void
160 read_gray(jas_matrix_t** pixels, uchar* scanline, int width)
161 {
162 	int32 x = 0;
163 	while (x < width) {
164 		scanline[x] = (uchar)jas_matrix_getv(pixels[0], x);
165 		x++;
166 	}
167 }
168 
169 
170 //!	Make *pixels[1] from gray1 scanline
171 inline void
172 write_gray1_to_gray(jas_matrix_t** pixels, uchar* scanline, int width)
173 {
174 	int32 x = 0;
175 	int32 index = 0;
176 	while (x < (width/8)) {
177 		unsigned char c = scanline[x++];
178 		for (int b = 128; b; b = b >> 1) {
179 			if (c & b)
180 				jas_matrix_setv(pixels[0], index++, 0);
181 			else
182 				jas_matrix_setv(pixels[0], index++, 255);
183 		}
184 	}
185 }
186 
187 
188 //!	Make *pixels[3] from gray1 scanline
189 inline void
190 write_gray1_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
191 {
192 	int32 x = 0;
193 	int32 index = 0;
194 	while (x < (width / 8)) {
195 		unsigned char c = scanline[x++];
196 		for (int b = 128; b; b = b >> 1) {
197 			if (c & b) {
198 				jas_matrix_setv(pixels[0], index, 0);
199 				jas_matrix_setv(pixels[1], index, 0);
200 				jas_matrix_setv(pixels[2], index, 0);
201 			} else {
202 				jas_matrix_setv(pixels[0], index, 255);
203 				jas_matrix_setv(pixels[1], index, 255);
204 				jas_matrix_setv(pixels[2], index, 255);
205 			}
206 			index++;
207 		}
208 	}
209 }
210 
211 
212 //!	Make *pixels[3] from cmap8 scanline
213 inline void
214 write_cmap8_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
215 {
216 	const color_map* map = system_colors();
217 	int32 x = 0;
218 	while (x < width) {
219 		rgb_color color = map->color_list[scanline[x]];
220 
221 		jas_matrix_setv(pixels[0], x, color.red);
222 		jas_matrix_setv(pixels[1], x, color.green);
223 		jas_matrix_setv(pixels[2], x, color.blue);
224 		x++;
225 	}
226 }
227 
228 
229 /*!
230 	Make *pixels[1] from gray scanline
231 	(just write data to pixels)
232 */
233 inline void
234 write_gray(jas_matrix_t** pixels, uchar* scanline, int width)
235 {
236 	int32 x = 0;
237 	while (x < width) {
238 		jas_matrix_setv(pixels[0], x, scanline[x]);
239 		x++;
240 	}
241 }
242 
243 
244 /*!
245 	Make *pixels[3] from RGB15/RGBA15 scanline
246 	(just write data to pixels)
247 */
248 inline void
249 write_rgb15_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
250 {
251 	int32 x = 0;
252 	int32 index = 0;
253 	int16 in_pixel;
254 	while (x < width) {
255 		in_pixel = scanline[index] | (scanline[index+1] << 8);
256 		index += 2;
257 
258 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7)
259 			| (((in_pixel & 0x7c00)) >> 12));
260 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2)
261 			| (((in_pixel & 0x3e0)) >> 7));
262 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
263 			| (((in_pixel & 0x1f)) >> 2));
264 		x++;
265 	}
266 }
267 
268 
269 /*!
270 	Make *pixels[3] from RGB15/RGBA15 bigendian scanline
271 	(just write data to pixels)
272 */
273 inline void
274 write_rgb15b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
275 {
276 	int32 x = 0;
277 	int32 index = 0;
278 	int16 in_pixel;
279 	while (x < width) {
280 		in_pixel = scanline[index + 1] | (scanline[index] << 8);
281 		index += 2;
282 
283 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7)
284 			| (((in_pixel & 0x7c00)) >> 12));
285 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2)
286 			| (((in_pixel & 0x3e0)) >> 7));
287 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
288 			| (((in_pixel & 0x1f)) >> 2));
289 		x++;
290 	}
291 }
292 
293 
294 /*!
295 	Make *pixels[3] from RGB16/RGBA16 scanline
296 	(just write data to pixels)
297 */
298 inline void
299 write_rgb16_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
300 {
301 	int32 x = 0;
302 	int32 index = 0;
303 	int16 in_pixel;
304 	while (x < width) {
305 		in_pixel = scanline[index] | (scanline[index+1] << 8);
306 		index += 2;
307 
308 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8)
309 			| (((in_pixel & 0x7c00)) >> 12));
310 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3)
311 			| (((in_pixel & 0x7e0)) >> 9));
312 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
313 			| (((in_pixel & 0x1f)) >> 2));
314 		x++;
315 	}
316 }
317 
318 
319 /*!
320 	Make *pixels[3] from RGB16/RGBA16 bigendian scanline
321 	(just write data to pixels)
322 */
323 inline void
324 write_rgb16b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
325 {
326 	int32 x = 0;
327 	int32 index = 0;
328 	int16 in_pixel;
329 	while (x < width) {
330 		in_pixel = scanline[index + 1] | (scanline[index] << 8);
331 		index += 2;
332 
333 		jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8)
334 			| (((in_pixel & 0xf800)) >> 13));
335 		jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3)
336 			| (((in_pixel & 0x7e0)) >> 9));
337 		jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
338 			| (((in_pixel & 0x1f)) >> 2));
339 		x++;
340 	}
341 }
342 
343 
344 /*!
345 	Make *pixels[3] from RGB24 scanline
346 	(just write data to pixels)
347 */
348 inline void
349 write_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
350 {
351 	int32 index = 0;
352 	int32 x = 0;
353 	while (x < width) {
354 		jas_matrix_setv(pixels[2], x, scanline[index++]);
355 		jas_matrix_setv(pixels[1], x, scanline[index++]);
356 		jas_matrix_setv(pixels[0], x, scanline[index++]);
357 		x++;
358 	}
359 }
360 
361 
362 /*!
363 	Make *pixels[3] from RGB24 bigendian scanline
364 	(just write data to pixels)
365 */
366 inline void
367 write_rgb24b(jas_matrix_t** pixels, uchar* scanline, int width)
368 {
369 	int32 index = 0;
370 	int32 x = 0;
371 	while (x < width) {
372 		jas_matrix_setv(pixels[0], x, scanline[index++]);
373 		jas_matrix_setv(pixels[1], x, scanline[index++]);
374 		jas_matrix_setv(pixels[2], x, scanline[index++]);
375 		x++;
376 	}
377 }
378 
379 
380 /*!
381 	Make *pixels[3] from RGB32 scanline
382 	(just write data to pixels)
383 */
384 inline void
385 write_rgb32_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
386 {
387 	int32 index = 0;
388 	int32 x = 0;
389 	while (x < width) {
390 		jas_matrix_setv(pixels[2], x, scanline[index++]);
391 		jas_matrix_setv(pixels[1], x, scanline[index++]);
392 		jas_matrix_setv(pixels[0], x, scanline[index++]);
393 		index++;
394 		x++;
395 	}
396 }
397 
398 
399 /*!
400 	Make *pixels[3] from RGB32 bigendian scanline
401 	(just write data to pixels)
402 */
403 inline void
404 write_rgb32b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
405 {
406 	int32 index = 0;
407 	int32 x = 0;
408 	while (x < width) {
409 		index++;
410 		jas_matrix_setv(pixels[0], x, scanline[index++]);
411 		jas_matrix_setv(pixels[1], x, scanline[index++]);
412 		jas_matrix_setv(pixels[2], x, scanline[index++]);
413 		x++;
414 	}
415 }
416 
417 
418 /*!
419 	Make *pixels[4] from RGBA32 scanline
420 	(just write data to pixels)
421 	!!! UNTESTED !!!
422 */
423 inline void
424 write_rgba32(jas_matrix_t** pixels, uchar* scanline, int width)
425 {
426 	int32 index = 0;
427 	int32 x = 0;
428 	while (x < width) {
429 		jas_matrix_setv(pixels[3], x, scanline[index++]);
430 		jas_matrix_setv(pixels[2], x, scanline[index++]);
431 		jas_matrix_setv(pixels[1], x, scanline[index++]);
432 		jas_matrix_setv(pixels[0], x, scanline[index++]);
433 		x++;
434 	}
435 }
436 
437 
438 /*!
439 	Make *pixels[4] from RGBA32 bigendian scanline
440 	(just write data to pixels)
441 	!!! UNTESTED !!!
442 */
443 inline void
444 write_rgba32b(jas_matrix_t** pixels, uchar* scanline, int width)
445 {
446 	int32 index = 0;
447 	int32 x = 0;
448 	while (x < width)
449 	{
450 		jas_matrix_setv(pixels[0], x, scanline[index++]);
451 		jas_matrix_setv(pixels[1], x, scanline[index++]);
452 		jas_matrix_setv(pixels[2], x, scanline[index++]);
453 		jas_matrix_setv(pixels[3], x, scanline[index++]);
454 		x++;
455 	}
456 }
457 
458 
459 }// end namespace conversion
460 
461 
462 //	#pragma mark -	jasper I/O
463 
464 
465 static int
466 Read(jas_stream_obj_t* object, char* buffer, const int length)
467 {
468 	return (*(BPositionIO**)object)->Read(buffer, length);
469 }
470 
471 
472 static int
473 Write(jas_stream_obj_t* object, char* buffer, const int length)
474 {
475 	return (*(BPositionIO**)object)->Write(buffer, length);
476 }
477 
478 
479 static long
480 Seek(jas_stream_obj_t* object, long offset, int origin)
481 {
482 	return (*(BPositionIO**)object)->Seek(offset, origin);
483 }
484 
485 
486 static int
487 Close(jas_stream_obj_t* object)
488 {
489 	return 0;
490 }
491 
492 
493 static jas_stream_ops_t positionIOops = {
494 	Read,
495 	Write,
496 	Seek,
497 	Close
498 };
499 
500 
501 static jas_stream_t*
502 jas_stream_positionIOopen(BPositionIO *positionIO)
503 {
504 	jas_stream_t* stream;
505 
506 	stream = (jas_stream_t *)malloc(sizeof(jas_stream_t));
507 	if (stream == (jas_stream_t *)NULL)
508 		return (jas_stream_t *)NULL;
509 
510 	memset(stream, 0, sizeof(jas_stream_t));
511 	stream->rwlimit_ = -1;
512 	stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*));
513 	if (stream->obj_ == (jas_stream_obj_t *)NULL) {
514 		free(stream);
515 		return (jas_stream_t *)NULL;
516 	}
517 
518 	*((BPositionIO**)stream->obj_) = positionIO;
519 	stream->ops_ = (&positionIOops);
520 	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
521 	stream->bufbase_ = stream->tinybuf_;
522 	stream->bufsize_ = 1;
523 	stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
524 	stream->ptr_ = stream->bufstart_;
525 	stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
526 
527 	return stream;
528 }
529 
530 
531 //	#pragma mark -
532 
533 
534 SSlider::SSlider(const char* name, const char* label,
535 		BMessage* message, int32 minValue, int32 maxValue, orientation posture,
536 		thumb_style thumbType, uint32 flags)
537 	:
538 	BSlider(name, label, message, minValue, maxValue,
539 		posture, thumbType, flags)
540 {
541 	rgb_color barColor = { 0, 0, 229, 255 };
542 	UseFillColor(true, &barColor);
543 }
544 
545 
546 //!	Update status string - show actual value
547 const char*
548 SSlider::UpdateText() const
549 {
550 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value());
551 	return fStatusLabel;
552 }
553 
554 
555 //	#pragma mark -
556 
557 
558 TranslatorReadView::TranslatorReadView(const char* name,
559 	TranslatorSettings* settings)
560 	:
561 	BView(name, 0, new BGroupLayout(B_VERTICAL)),
562 	fSettings(settings)
563 {
564 	fGrayAsRGB32 = new BCheckBox("grayasrgb32",
565 		B_TRANSLATE("Read greyscale images as RGB32"),
566 		new BMessage(VIEW_MSG_SET_GRAYASRGB32));
567 	if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32))
568 		fGrayAsRGB32->SetValue(B_CONTROL_ON);
569 
570 	float padding = 10.0f;
571 	BLayoutBuilder::Group<>(this, B_VERTICAL)
572 		.SetInsets(padding)
573 		.Add(fGrayAsRGB32)
574 		.AddGlue();
575 }
576 
577 
578 TranslatorReadView::~TranslatorReadView()
579 {
580 	fSettings->Release();
581 }
582 
583 
584 void
585 TranslatorReadView::AttachedToWindow()
586 {
587 	fGrayAsRGB32->SetTarget(this);
588 }
589 
590 
591 void
592 TranslatorReadView::MessageReceived(BMessage* message)
593 {
594 	switch (message->what) {
595 		case VIEW_MSG_SET_GRAYASRGB32:
596 		{
597 			int32 value;
598 			if (message->FindInt32("be:value", &value) == B_OK) {
599 				bool boolValue = value;
600 				fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32, &boolValue);
601 				fSettings->SaveSettings();
602 			}
603 			break;
604 		}
605 		default:
606 			BView::MessageReceived(message);
607 			break;
608 	}
609 }
610 
611 
612 //	#pragma mark - TranslatorWriteView
613 
614 
615 TranslatorWriteView::TranslatorWriteView(const char* name,
616 	TranslatorSettings* settings)
617 	:
618 	BView(name, 0, new BGroupLayout(B_VERTICAL)),
619 	fSettings(settings)
620 {
621 	fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"),
622 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
623 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
624 	fQualitySlider->SetHashMarkCount(10);
625 	fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High"));
626 	fQualitySlider->SetValue(fSettings->SetGetInt32(JP2_SET_QUALITY));
627 
628 	fGrayAsRGB24 = new BCheckBox("gray1asrgb24",
629 		B_TRANSLATE("Write black-and-white images as RGB24"),
630 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
631 	if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24))
632 		fGrayAsRGB24->SetValue(B_CONTROL_ON);
633 
634 	fCodeStreamOnly = new BCheckBox("codestreamonly",
635 		B_TRANSLATE("Output only codestream (.jpc)"),
636 		new BMessage(VIEW_MSG_SET_JPC));
637 	if (fSettings->SetGetBool(JP2_SET_JPC))
638 		fCodeStreamOnly->SetValue(B_CONTROL_ON);
639 
640 	float padding = 10.0f;
641 	BLayoutBuilder::Group<>(this, B_VERTICAL, padding)
642 		.SetInsets(padding)
643 		.Add(fQualitySlider)
644 		.Add(fGrayAsRGB24)
645 		.Add(fCodeStreamOnly)
646 		.AddGlue();
647 }
648 
649 
650 TranslatorWriteView::~TranslatorWriteView()
651 {
652 	fSettings->Release();
653 }
654 
655 
656 void
657 TranslatorWriteView::AttachedToWindow()
658 {
659 	fQualitySlider->SetTarget(this);
660 	fGrayAsRGB24->SetTarget(this);
661 	fCodeStreamOnly->SetTarget(this);
662 }
663 
664 
665 void
666 TranslatorWriteView::MessageReceived(BMessage* message)
667 {
668 	switch (message->what) {
669 		case VIEW_MSG_SET_QUALITY:
670 		{
671 			int32 value;
672 			if (message->FindInt32("be:value", &value) == B_OK) {
673 				fSettings->SetGetInt32(JP2_SET_QUALITY, &value);
674 				fSettings->SaveSettings();
675 			}
676 			break;
677 		}
678 		case VIEW_MSG_SET_GRAY1ASRGB24:
679 		{
680 			int32 value;
681 			if (message->FindInt32("be:value", &value) == B_OK) {
682 				bool boolValue = value;
683 				fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24, &boolValue);
684 				fSettings->SaveSettings();
685 			}
686 			break;
687 		}
688 		case VIEW_MSG_SET_JPC:
689 		{
690 			int32 value;
691 			if (message->FindInt32("be:value", &value) == B_OK) {
692 				bool boolValue = value;
693 				fSettings->SetGetBool(JP2_SET_JPC, &boolValue);
694 				fSettings->SaveSettings();
695 			}
696 			break;
697 		}
698 		default:
699 			BView::MessageReceived(message);
700 			break;
701 	}
702 }
703 
704 
705 //	#pragma mark -
706 
707 
708 TranslatorAboutView::TranslatorAboutView(const char* name)
709 	:
710 	BView(name, 0, new BGroupLayout(B_VERTICAL))
711 {
712 	BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
713 	BStringView* title = new BStringView("Title", sTranslatorName);
714 	title->SetFont(be_bold_font);
715 	title->SetExplicitAlignment(labelAlignment);
716 
717 	char versionString[16];
718 	sprintf(versionString, "v%d.%d.%d",
719 		static_cast<int>(sTranslatorVersion >> 8),
720 		static_cast<int>((sTranslatorVersion >> 4) & 0xf),
721 		static_cast<int>(sTranslatorVersion & 0xf));
722 
723 	BStringView* version = new BStringView("Version", versionString);
724 	version->SetExplicitAlignment(labelAlignment);
725 
726 	BTextView* infoView = new BTextView("info");
727 	infoView->SetText(sTranslatorInfo);
728 	infoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
729 	infoView->MakeEditable(false);
730 
731 	float padding = 10.0f;
732 	BLayoutBuilder::Group<>(this, B_VERTICAL, padding)
733 		.SetInsets(padding)
734 		.AddGroup(B_HORIZONTAL, padding)
735 			.Add(title)
736 			.Add(version)
737 			.AddGlue()
738 		.End()
739 		.Add(infoView);
740 }
741 
742 
743 //	#pragma mark -
744 
745 
746 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings)
747 	:
748 	BTabView(name)
749 {
750 	AddTab(new TranslatorWriteView(B_TRANSLATE("Write"),
751 		settings->Acquire()));
752 	AddTab(new TranslatorReadView(B_TRANSLATE("Read"),
753 		settings->Acquire()));
754 	AddTab(new TranslatorAboutView(B_TRANSLATE("About")));
755 
756 	settings->Release();
757 
758  	BFont font;
759  	GetFont(&font);
760  	SetExplicitPreferredSize(
761 		BSize((font.Size() * 380) / 12, (font.Size() * 250) / 12));
762 }
763 
764 
765 //	#pragma mark -
766 
767 BView*
768 JP2Translator::NewConfigView(TranslatorSettings* settings)
769 {
770 	BView* outView = new TranslatorView("TranslatorView", settings);
771 	return outView;
772 }
773 
774 
775 JP2Translator::JP2Translator()
776 	: BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion,
777 		sInputFormats, kNumInputFormats,
778 		sOutputFormats, kNumOutputFormats,
779 		JP2_SETTINGS_FILE,
780 		sDefaultSettings, kNumDefaultSettings,
781 		B_TRANSLATOR_BITMAP, JP2_FORMAT)
782 {
783 }
784 
785 
786 //!	Determine whether or not we can handle this data
787 status_t
788 JP2Translator::DerivedIdentify(BPositionIO* inSource,
789 	const translation_format* inFormat, BMessage* ioExtension,
790 	translator_info* outInfo, uint32 outType)
791 {
792 	if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP)
793 		&& outType != JP2_FORMAT)
794 		return B_NO_TRANSLATOR;
795 
796 	// !!! You might need to make this buffer bigger to test for your
797 	// native format
798 	off_t position = inSource->Position();
799 	uint8 header[sizeof(TranslatorBitmap)];
800 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
801 	inSource->Seek(position, SEEK_SET);
802 	if (err < B_OK)
803 		return err;
804 
805 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic)
806 		== B_TRANSLATOR_BITMAP) {
807 		if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK)
808 			return B_NO_TRANSLATOR;
809 	} else {
810 		if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8)
811 			| header[7]) == JP2_BOX_JP) // JP2
812 			|| (header[0] == (JPC_MS_SOC >> 8) && header[1]
813 			== (JPC_MS_SOC & 0xff)))	// JPC
814 		{
815 			if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK)
816 				return B_NO_TRANSLATOR;
817 		} else
818 			return B_NO_TRANSLATOR;
819 	}
820 
821 	return B_OK;
822 }
823 
824 
825 status_t
826 JP2Translator::DerivedTranslate(BPositionIO* inSource,
827 	const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
828 	BPositionIO* outDestination, int32 baseType)
829 {
830 	// If no specific type was requested, convert to the interchange format
831 	if (outType == 0)
832 		outType = B_TRANSLATOR_BITMAP;
833 
834 	// What action to take, based on the findings of Identify()
835 	if (outType == inInfo->type)
836 		return Copy(inSource, outDestination);
837 	if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT)
838 		return Compress(inSource, outDestination);
839 	if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP)
840 		return Decompress(inSource, outDestination);
841 
842 	return B_NO_TRANSLATOR;
843 }
844 
845 
846 //!	The user has requested the same format for input and output, so just copy
847 status_t
848 JP2Translator::Copy(BPositionIO* in, BPositionIO* out)
849 {
850 	int block_size = 65536;
851 	void* buffer = malloc(block_size);
852 	char temp[1024];
853 	if (buffer == NULL) {
854 		buffer = temp;
855 		block_size = 1024;
856 	}
857 	status_t err = B_OK;
858 
859 	// Read until end of file or error
860 	while (1) {
861 		ssize_t to_read = block_size;
862 		err = in->Read(buffer, to_read);
863 		// Explicit check for EOF
864 		if (err == -1) {
865 			if (buffer != temp)
866 				free(buffer);
867 			return B_OK;
868 		}
869 		if (err <= B_OK) break;
870 		to_read = err;
871 		err = out->Write(buffer, to_read);
872 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
873 		if (err < B_OK) break;
874 	}
875 
876 	if (buffer != temp)
877 		free(buffer);
878 	return (err >= 0) ? B_OK : err;
879 }
880 
881 
882 //!	Encode into the native format
883 status_t
884 JP2Translator::Compress(BPositionIO* in, BPositionIO* out)
885 {
886 	using namespace conversion;
887 
888 	// Read info about bitmap
889 	TranslatorBitmap header;
890 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
891 	if (err < B_OK)
892 		return err;
893 	if (err < (int)sizeof(TranslatorBitmap))
894 		return B_ERROR;
895 
896 	// Grab dimension, color space, and size information from the stream
897 	BRect bounds;
898 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
899 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
900 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
901 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
902 
903 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
904 
905 	int width = bounds.IntegerWidth() + 1;
906 	int height = bounds.IntegerHeight() + 1;
907 
908 	// Function pointer to write function
909 	// It MUST point to proper function
910 	void (*converter)(jas_matrix_t** pixels, uchar* inscanline,
911 		int width) = write_rgba32;
912 
913 	// Default color info
914 	int out_color_space = JAS_CLRSPC_SRGB;
915 	int out_color_components = 3;
916 
917 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
918 		case B_GRAY1:
919 			if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) {
920 				converter = write_gray1_to_rgb24;
921 			} else {
922 				out_color_components = 1;
923 				out_color_space = JAS_CLRSPC_SGRAY;
924 				converter = write_gray1_to_gray;
925 			}
926 			break;
927 
928 		case B_CMAP8:
929 			converter = write_cmap8_to_rgb24;
930 			break;
931 
932 		case B_GRAY8:
933 			out_color_components = 1;
934 			out_color_space = JAS_CLRSPC_SGRAY;
935 			converter = write_gray;
936 			break;
937 
938 		case B_RGB15:
939 		case B_RGBA15:
940 			converter = write_rgb15_to_rgb24;
941 			break;
942 
943 		case B_RGB15_BIG:
944 		case B_RGBA15_BIG:
945 			converter = write_rgb15b_to_rgb24;
946 			break;
947 
948 		case B_RGB16:
949 			converter = write_rgb16_to_rgb24;
950 			break;
951 
952 		case B_RGB16_BIG:
953 			converter = write_rgb16b_to_rgb24;
954 			break;
955 
956 		case B_RGB24:
957 			converter = write_rgb24;
958 			break;
959 
960 		case B_RGB24_BIG:
961 			converter = write_rgb24b;
962 			break;
963 
964 		case B_RGB32:
965 			converter = write_rgb32_to_rgb24;
966 			break;
967 
968 		case B_RGB32_BIG:
969 			converter = write_rgb32b_to_rgb24;
970 			break;
971 
972 		case B_RGBA32:
973 		/*
974 			// In theory it should be possible to write 4 color components
975 			// to jp2, so it should be possible to have transparency.
976 			// Unfortunetly libjasper does not agree with that
977 			// For now i don't know how to modify it :(
978 
979 			out_color_components = 4;
980 			converter = write_rgba32;
981 		*/
982 			converter = write_rgb32_to_rgb24;
983 			break;
984 
985 		case B_RGBA32_BIG:
986 		/*
987 			// In theory it should be possible to write 4 color components
988 			// to jp2, so it should be possible to have transparency.
989 			// Unfortunetly libjasper does not agree with that
990 			// For now i don't know how to modify it :(
991 
992 			out_color_components = 4;
993 			converter = write_rgba32b;
994 		*/
995 			converter = write_rgb32b_to_rgb24;
996 			break;
997 
998 		default:
999 			syslog(LOG_ERR, "Unknown color space.\n");
1000 			return B_ERROR;
1001 	}
1002 
1003 	jas_image_t* image;
1004 	jas_stream_t* outs;
1005 	jas_matrix_t* pixels[4];
1006 	jas_image_cmptparm_t component_info[4];
1007 
1008 	if (jas_init())
1009 		return B_ERROR;
1010 
1011 	if (!(outs = jas_stream_positionIOopen(out)))
1012 		return B_ERROR;
1013 
1014 	int32 i = 0;
1015 	for (i = 0; i < (long)out_color_components; i++) {
1016 		(void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t));
1017 		component_info[i].hstep = 1;
1018 		component_info[i].vstep = 1;
1019 		component_info[i].width = (unsigned int)width;
1020 		component_info[i].height = (unsigned int)height;
1021 		component_info[i].prec = (unsigned int)8;
1022 	}
1023 
1024 	image = jas_image_create((short)out_color_components, component_info,
1025 		out_color_space);
1026 	if (image == (jas_image_t *)NULL)
1027 		return Error(outs, NULL, NULL, 0, NULL, B_ERROR);
1028 
1029 	uchar *in_scanline = (uchar*) malloc(in_row_bytes);
1030 	if (in_scanline == NULL)
1031 		return Error(outs, image, NULL, 0, NULL, B_ERROR);
1032 
1033 	for (i = 0; i < (long)out_color_components; i++) {
1034 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1035 		if (pixels[i] == (jas_matrix_t *)NULL)
1036 			return Error(outs, image, pixels, i+1, in_scanline, B_ERROR);
1037 	}
1038 
1039 	int32 y = 0;
1040 	for (y = 0; y < (long)height; y++) {
1041 		err = in->Read(in_scanline, in_row_bytes);
1042 		if (err < in_row_bytes) {
1043 			return (err < B_OK) ? Error(outs, image, pixels,
1044 					out_color_components, in_scanline, err)
1045 				: Error(outs, image, pixels, out_color_components, in_scanline,
1046 					B_ERROR);
1047 		}
1048 
1049 		converter(pixels, in_scanline, width);
1050 
1051 		for (i = 0; i < (long)out_color_components; i++) {
1052 			(void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y,
1053 				(unsigned int)width, 1, pixels[i]);
1054 		}
1055 	}
1056 
1057 	char opts[16];
1058 	sprintf(opts, "rate=%1f",
1059 		(float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0);
1060 
1061 	if (jas_image_encode(image, outs, jas_image_strtofmt(
1062 			fSettings->SetGetBool(JP2_SET_JPC) ?
1063 				(char*)"jpc" : (char*)"jp2"), opts)) {
1064 		return Error(outs, image, pixels,
1065 			out_color_components, in_scanline, err);
1066 	}
1067 
1068 	free(in_scanline);
1069 
1070 	for (i = 0; i < (long)out_color_components; i++)
1071 		jas_matrix_destroy(pixels[i]);
1072 
1073 	jas_stream_close(outs);
1074 	jas_image_destroy(image);
1075 	jas_image_clearfmts();
1076 
1077 	return B_OK;
1078 }
1079 
1080 
1081 //!	Decode the native format
1082 status_t
1083 JP2Translator::Decompress(BPositionIO* in, BPositionIO* out)
1084 {
1085 	using namespace conversion;
1086 
1087 	jas_image_t* image;
1088 	jas_stream_t* ins;
1089 	jas_matrix_t* pixels[4];
1090 
1091 	if (jas_init())
1092 		return B_ERROR;
1093 
1094 	if (!(ins = jas_stream_positionIOopen(in)))
1095 		return B_ERROR;
1096 
1097 	if (!(image = jas_image_decode(ins, -1, 0)))
1098 		return Error(ins, NULL, NULL, 0, NULL, B_ERROR);
1099 
1100 	// Default color info
1101 	color_space out_color_space;
1102 	int out_color_components;
1103 	int	in_color_components = jas_image_numcmpts(image);
1104 
1105 	// Function pointer to read function
1106 	// It MUST point to proper function
1107 	void (*converter)(jas_matrix_t** pixels, uchar* outscanline,
1108 		int width) = NULL;
1109 
1110 	switch (jas_clrspc_fam(jas_image_clrspc(image))) {
1111 		case JAS_CLRSPC_FAM_RGB:
1112 			out_color_components = 4;
1113 			if (in_color_components == 3) {
1114 				out_color_space = B_RGB32;
1115 				converter = read_rgb24_to_rgb32;
1116 			} else if (in_color_components == 4) {
1117 				out_color_space = B_RGBA32;
1118 				converter = read_rgba32;
1119 			} else {
1120 				syslog(LOG_ERR, "Other than RGB with 3 or 4 color "
1121 					"components not implemented.\n");
1122 				return Error(ins, image, NULL, 0, NULL, B_ERROR);
1123 			}
1124 			break;
1125 		case JAS_CLRSPC_FAM_GRAY:
1126 			if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) {
1127 				out_color_space = B_RGB32;
1128 				out_color_components = 4;
1129 				converter = read_gray_to_rgb32;
1130 			} else {
1131 				out_color_space = B_GRAY8;
1132 				out_color_components = 1;
1133 				converter = read_gray;
1134 			}
1135 			break;
1136 		case JAS_CLRSPC_FAM_YCBCR:
1137 			syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n");
1138 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1139 			break;
1140 		case JAS_CLRSPC_UNKNOWN:
1141 		default:
1142 			syslog(LOG_ERR, "Color space unknown. \n");
1143 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1144 			break;
1145 	}
1146 
1147 	float width = (float)jas_image_width(image);
1148 	float height = (float)jas_image_height(image);
1149 
1150 	// Bytes count in one line of image (scanline)
1151 	int64 out_row_bytes = (int32)width * out_color_components;
1152 		// NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits
1153 
1154 	// !!! Initialize this bounds rect to the size of your image
1155 	BRect bounds(0, 0, width - 1, height - 1);
1156 
1157 
1158 	// Fill out the B_TRANSLATOR_BITMAP's header
1159 	TranslatorBitmap header;
1160 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
1161 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
1162 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
1163 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
1164 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
1165 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
1166 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes);
1167 	header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height));
1168 
1169 	// Write out the header
1170 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1171 	if (err < B_OK)
1172 		return Error(ins, image, NULL, 0, NULL, err);
1173 	if (err < (int)sizeof(TranslatorBitmap))
1174 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1175 
1176 	uchar *out_scanline = (uchar*) malloc(out_row_bytes);
1177 	if (out_scanline == NULL)
1178 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1179 
1180 	int32 i = 0;
1181 	for (i = 0; i < (long)in_color_components; i++) {
1182 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1183 		if (pixels[i] == (jas_matrix_t *)NULL)
1184 			return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR);
1185 	}
1186 
1187 	int32 y = 0;
1188 	for (y = 0; y < (long)height; y++) {
1189 		for (i = 0; i < (long)in_color_components; i++) {
1190 			(void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y,
1191 				(unsigned int)width, 1, pixels[i]);
1192 		}
1193 
1194 		converter(pixels, out_scanline, (int32)width);
1195 
1196 		err = out->Write(out_scanline, out_row_bytes);
1197 		if (err < out_row_bytes) {
1198 			return (err < B_OK) ? Error(ins, image, pixels, in_color_components,
1199 				out_scanline, err)
1200 				: Error(ins, image, pixels, in_color_components, out_scanline,
1201 					B_ERROR);
1202 		}
1203 	}
1204 
1205 	free(out_scanline);
1206 
1207 	for (i = 0; i < (long)in_color_components; i++)
1208 		jas_matrix_destroy(pixels[i]);
1209 
1210 	jas_stream_close(ins);
1211 	jas_image_destroy(image);
1212 	jas_image_clearfmts();
1213 
1214 	return B_OK;
1215 }
1216 
1217 
1218 /*! searches in both inputFormats & outputFormats */
1219 status_t
1220 JP2Translator::PopulateInfoFromFormat(translator_info* info,
1221 	uint32 formatType, translator_id id)
1222 {
1223 	int32 formatCount;
1224 	const translation_format* formats = OutputFormats(&formatCount);
1225 
1226 	for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) {
1227 		if (PopulateInfoFromFormat(info, formatType,
1228 			formats, formatCount) == B_OK) {
1229 			info->translator = id;
1230 			return B_OK;
1231 		}
1232 	}
1233 
1234 	return B_ERROR;
1235 }
1236 
1237 
1238 status_t
1239 JP2Translator::PopulateInfoFromFormat(translator_info* info,
1240 	uint32 formatType, const translation_format* formats, int32 formatCount)
1241 {
1242 	for (int i = 0; i < formatCount; i++) {
1243 		if (formats[i].type == formatType) {
1244 			info->type = formatType;
1245 			info->group = formats[i].group;
1246 			info->quality = formats[i].quality;
1247 			info->capability = formats[i].capability;
1248 			if (strncmp(formats[i].name,
1249 				"Be Bitmap Format (JPEG2000Translator)",
1250 				sizeof("Be Bitmap Format (JPEG2000Translator)")) == 0)
1251 				strncpy(info->name,
1252 					B_TRANSLATE("Be Bitmap Format (JPEG2000Translator)"),
1253 					sizeof(info->name));
1254 			else
1255 				strncpy(info->name, formats[i].name, sizeof(info->name));
1256 			strncpy(info->MIME,  formats[i].MIME, sizeof(info->MIME));
1257 			return B_OK;
1258 		}
1259 	}
1260 
1261 	return B_ERROR;
1262 }
1263 
1264 
1265 /*!
1266 	Frees jpeg alocated memory
1267 	Returns given error (B_ERROR by default)
1268 */
1269 status_t
1270 Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels,
1271 	int32 pixels_count, uchar* scanline, status_t error)
1272 {
1273 	if (pixels) {
1274 		int32 i;
1275 		for (i = 0; i < (long)pixels_count; i++) {
1276 			if (pixels[i] != NULL)
1277 				jas_matrix_destroy(pixels[i]);
1278 		}
1279 	}
1280 	if (stream)
1281 		jas_stream_close(stream);
1282 	if (image)
1283 		jas_image_destroy(image);
1284 
1285 	jas_image_clearfmts();
1286 	free(scanline);
1287 
1288 	return error;
1289 }
1290 
1291 
1292 //	#pragma mark -
1293 
1294 BTranslator*
1295 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
1296 {
1297 	if (!n)
1298 		return new JP2Translator();
1299 
1300 	return NULL;
1301 }
1302 
1303 
1304 int
1305 main()
1306 {
1307 	BApplication app("application/x-vnd.Haiku-JPEG2000Translator");
1308 	JP2Translator* translator = new JP2Translator();
1309 	if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK)
1310 		app.Run();
1311 
1312 	return 0;
1313 }
1314 
1315