xref: /haiku/src/add-ons/translators/jpeg2000/JPEG2000Translator.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 		jas_matrix_setv(pixels[0], x, scanline[index++]);
450 		jas_matrix_setv(pixels[1], x, scanline[index++]);
451 		jas_matrix_setv(pixels[2], x, scanline[index++]);
452 		jas_matrix_setv(pixels[3], x, scanline[index++]);
453 		x++;
454 	}
455 }
456 
457 
458 }// end namespace conversion
459 
460 
461 //	#pragma mark -	jasper I/O
462 
463 
464 static int
465 Read(jas_stream_obj_t* object, char* buffer, const int length)
466 {
467 	return (*(BPositionIO**)object)->Read(buffer, length);
468 }
469 
470 
471 static int
472 Write(jas_stream_obj_t* object, char* buffer, const int length)
473 {
474 	return (*(BPositionIO**)object)->Write(buffer, length);
475 }
476 
477 
478 static long
479 Seek(jas_stream_obj_t* object, long offset, int origin)
480 {
481 	return (*(BPositionIO**)object)->Seek(offset, origin);
482 }
483 
484 
485 static int
486 Close(jas_stream_obj_t* object)
487 {
488 	return 0;
489 }
490 
491 
492 static jas_stream_ops_t positionIOops = {
493 	Read,
494 	Write,
495 	Seek,
496 	Close
497 };
498 
499 
500 static jas_stream_t*
501 jas_stream_positionIOopen(BPositionIO *positionIO)
502 {
503 	jas_stream_t* stream;
504 
505 	stream = (jas_stream_t *)malloc(sizeof(jas_stream_t));
506 	if (stream == (jas_stream_t *)NULL)
507 		return (jas_stream_t *)NULL;
508 
509 	memset(stream, 0, sizeof(jas_stream_t));
510 	stream->rwlimit_ = -1;
511 	stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*));
512 	if (stream->obj_ == (jas_stream_obj_t *)NULL) {
513 		free(stream);
514 		return (jas_stream_t *)NULL;
515 	}
516 
517 	*((BPositionIO**)stream->obj_) = positionIO;
518 	stream->ops_ = (&positionIOops);
519 	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
520 	stream->bufbase_ = stream->tinybuf_;
521 	stream->bufsize_ = 1;
522 	stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
523 	stream->ptr_ = stream->bufstart_;
524 	stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
525 
526 	return stream;
527 }
528 
529 
530 //	#pragma mark -
531 
532 
533 SSlider::SSlider(const char* name, const char* label,
534 		BMessage* message, int32 minValue, int32 maxValue, orientation posture,
535 		thumb_style thumbType, uint32 flags)
536 	:
537 	BSlider(name, label, message, minValue, maxValue,
538 		posture, thumbType, flags)
539 {
540 	rgb_color barColor = { 0, 0, 229, 255 };
541 	UseFillColor(true, &barColor);
542 }
543 
544 
545 //!	Update status string - show actual value
546 const char*
547 SSlider::UpdateText() const
548 {
549 	snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value());
550 	return fStatusLabel;
551 }
552 
553 
554 //	#pragma mark -
555 
556 
557 TranslatorReadView::TranslatorReadView(const char* name,
558 	TranslatorSettings* settings)
559 	:
560 	BView(name, 0, new BGroupLayout(B_VERTICAL)),
561 	fSettings(settings)
562 {
563 	fGrayAsRGB32 = new BCheckBox("grayasrgb32",
564 		B_TRANSLATE("Read greyscale images as RGB32"),
565 		new BMessage(VIEW_MSG_SET_GRAYASRGB32));
566 	if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32))
567 		fGrayAsRGB32->SetValue(B_CONTROL_ON);
568 
569 	float padding = 10.0f;
570 	BLayoutBuilder::Group<>(this, B_VERTICAL)
571 		.SetInsets(padding)
572 		.Add(fGrayAsRGB32)
573 		.AddGlue();
574 }
575 
576 
577 TranslatorReadView::~TranslatorReadView()
578 {
579 	fSettings->Release();
580 }
581 
582 
583 void
584 TranslatorReadView::AttachedToWindow()
585 {
586 	fGrayAsRGB32->SetTarget(this);
587 }
588 
589 
590 void
591 TranslatorReadView::MessageReceived(BMessage* message)
592 {
593 	switch (message->what) {
594 		case VIEW_MSG_SET_GRAYASRGB32:
595 		{
596 			int32 value;
597 			if (message->FindInt32("be:value", &value) == B_OK) {
598 				bool boolValue = value;
599 				fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32, &boolValue);
600 				fSettings->SaveSettings();
601 			}
602 			break;
603 		}
604 		default:
605 			BView::MessageReceived(message);
606 			break;
607 	}
608 }
609 
610 
611 //	#pragma mark - TranslatorWriteView
612 
613 
614 TranslatorWriteView::TranslatorWriteView(const char* name,
615 	TranslatorSettings* settings)
616 	:
617 	BView(name, 0, new BGroupLayout(B_VERTICAL)),
618 	fSettings(settings)
619 {
620 	fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"),
621 		new BMessage(VIEW_MSG_SET_QUALITY), 0, 100);
622 	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
623 	fQualitySlider->SetHashMarkCount(10);
624 	fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High"));
625 	fQualitySlider->SetValue(fSettings->SetGetInt32(JP2_SET_QUALITY));
626 
627 	fGrayAsRGB24 = new BCheckBox("gray1asrgb24",
628 		B_TRANSLATE("Write black-and-white images as RGB24"),
629 		new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
630 	if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24))
631 		fGrayAsRGB24->SetValue(B_CONTROL_ON);
632 
633 	fCodeStreamOnly = new BCheckBox("codestreamonly",
634 		B_TRANSLATE("Output only codestream (.jpc)"),
635 		new BMessage(VIEW_MSG_SET_JPC));
636 	if (fSettings->SetGetBool(JP2_SET_JPC))
637 		fCodeStreamOnly->SetValue(B_CONTROL_ON);
638 
639 	BLayoutBuilder::Group<>(this, B_VERTICAL)
640 		.SetInsets(B_USE_DEFAULT_SPACING)
641 		.Add(fQualitySlider)
642 		.Add(fGrayAsRGB24)
643 		.Add(fCodeStreamOnly)
644 		.AddGlue();
645 }
646 
647 
648 TranslatorWriteView::~TranslatorWriteView()
649 {
650 	fSettings->Release();
651 }
652 
653 
654 void
655 TranslatorWriteView::AttachedToWindow()
656 {
657 	fQualitySlider->SetTarget(this);
658 	fGrayAsRGB24->SetTarget(this);
659 	fCodeStreamOnly->SetTarget(this);
660 }
661 
662 
663 void
664 TranslatorWriteView::MessageReceived(BMessage* message)
665 {
666 	switch (message->what) {
667 		case VIEW_MSG_SET_QUALITY:
668 		{
669 			int32 value;
670 			if (message->FindInt32("be:value", &value) == B_OK) {
671 				fSettings->SetGetInt32(JP2_SET_QUALITY, &value);
672 				fSettings->SaveSettings();
673 			}
674 			break;
675 		}
676 		case VIEW_MSG_SET_GRAY1ASRGB24:
677 		{
678 			int32 value;
679 			if (message->FindInt32("be:value", &value) == B_OK) {
680 				bool boolValue = value;
681 				fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24, &boolValue);
682 				fSettings->SaveSettings();
683 			}
684 			break;
685 		}
686 		case VIEW_MSG_SET_JPC:
687 		{
688 			int32 value;
689 			if (message->FindInt32("be:value", &value) == B_OK) {
690 				bool boolValue = value;
691 				fSettings->SetGetBool(JP2_SET_JPC, &boolValue);
692 				fSettings->SaveSettings();
693 			}
694 			break;
695 		}
696 		default:
697 			BView::MessageReceived(message);
698 			break;
699 	}
700 }
701 
702 
703 //	#pragma mark -
704 
705 
706 TranslatorAboutView::TranslatorAboutView(const char* name)
707 	:
708 	BView(name, 0, new BGroupLayout(B_VERTICAL))
709 {
710 	BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
711 	BStringView* title = new BStringView("Title", sTranslatorName);
712 	title->SetFont(be_bold_font);
713 	title->SetExplicitAlignment(labelAlignment);
714 
715 	char versionString[100];
716 	snprintf(versionString, sizeof(versionString),
717 		B_TRANSLATE("Version %d.%d.%d"),
718 		static_cast<int>(sTranslatorVersion >> 8),
719 		static_cast<int>((sTranslatorVersion >> 4) & 0xf),
720 		static_cast<int>(sTranslatorVersion & 0xf));
721 
722 	BStringView* version = new BStringView("Version", versionString);
723 	version->SetExplicitAlignment(labelAlignment);
724 
725 	BTextView* infoView = new BTextView("info");
726 	infoView->SetText(sTranslatorInfo);
727 	infoView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
728 	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
729 	infoView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
730 	infoView->MakeEditable(false);
731 
732 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
733 		.SetInsets(B_USE_DEFAULT_SPACING)
734 		.Add(title)
735 		.Add(version)
736 		.Add(infoView);
737 }
738 
739 
740 //	#pragma mark -
741 
742 
743 TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings)
744 	:
745 	BTabView(name, B_WIDTH_FROM_LABEL)
746 {
747 	SetBorder(B_NO_BORDER);
748 
749 	AddTab(new TranslatorWriteView(B_TRANSLATE("Write"),
750 		settings->Acquire()));
751 	AddTab(new TranslatorReadView(B_TRANSLATE("Read"),
752 		settings->Acquire()));
753 	AddTab(new TranslatorAboutView(B_TRANSLATE("About")));
754 
755 	settings->Release();
756 }
757 
758 
759 //	#pragma mark -
760 
761 BView*
762 JP2Translator::NewConfigView(TranslatorSettings* settings)
763 {
764 	BView* outView = new TranslatorView("TranslatorView", settings);
765 	return outView;
766 }
767 
768 
769 JP2Translator::JP2Translator()
770 	: BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion,
771 		sInputFormats, kNumInputFormats,
772 		sOutputFormats, kNumOutputFormats,
773 		JP2_SETTINGS_FILE,
774 		sDefaultSettings, kNumDefaultSettings,
775 		B_TRANSLATOR_BITMAP, JP2_FORMAT)
776 {
777 }
778 
779 
780 //!	Determine whether or not we can handle this data
781 status_t
782 JP2Translator::DerivedIdentify(BPositionIO* inSource,
783 	const translation_format* inFormat, BMessage* ioExtension,
784 	translator_info* outInfo, uint32 outType)
785 {
786 	if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP)
787 		&& outType != JP2_FORMAT)
788 		return B_NO_TRANSLATOR;
789 
790 	// !!! You might need to make this buffer bigger to test for your
791 	// native format
792 	off_t position = inSource->Position();
793 	uint8 header[sizeof(TranslatorBitmap)];
794 	status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
795 	inSource->Seek(position, SEEK_SET);
796 	if (err < B_OK)
797 		return err;
798 
799 	if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic)
800 		== B_TRANSLATOR_BITMAP) {
801 		if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK)
802 			return B_NO_TRANSLATOR;
803 	} else {
804 		if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8)
805 			| header[7]) == JP2_BOX_JP) // JP2
806 			|| (header[0] == (JPC_MS_SOC >> 8) && header[1]
807 			== (JPC_MS_SOC & 0xff)))	// JPC
808 		{
809 			if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK)
810 				return B_NO_TRANSLATOR;
811 		} else
812 			return B_NO_TRANSLATOR;
813 	}
814 
815 	return B_OK;
816 }
817 
818 
819 status_t
820 JP2Translator::DerivedTranslate(BPositionIO* inSource,
821 	const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
822 	BPositionIO* outDestination, int32 baseType)
823 {
824 	// If no specific type was requested, convert to the interchange format
825 	if (outType == 0)
826 		outType = B_TRANSLATOR_BITMAP;
827 
828 	// What action to take, based on the findings of Identify()
829 	if (outType == inInfo->type)
830 		return Copy(inSource, outDestination);
831 	if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT)
832 		return Compress(inSource, outDestination);
833 	if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP)
834 		return Decompress(inSource, outDestination);
835 
836 	return B_NO_TRANSLATOR;
837 }
838 
839 
840 //!	The user has requested the same format for input and output, so just copy
841 status_t
842 JP2Translator::Copy(BPositionIO* in, BPositionIO* out)
843 {
844 	int block_size = 65536;
845 	void* buffer = malloc(block_size);
846 	char temp[1024];
847 	if (buffer == NULL) {
848 		buffer = temp;
849 		block_size = 1024;
850 	}
851 	status_t err = B_OK;
852 
853 	// Read until end of file or error
854 	while (1) {
855 		ssize_t to_read = block_size;
856 		err = in->Read(buffer, to_read);
857 		// Explicit check for EOF
858 		if (err == -1) {
859 			if (buffer != temp)
860 				free(buffer);
861 			return B_OK;
862 		}
863 		if (err <= B_OK) break;
864 		to_read = err;
865 		err = out->Write(buffer, to_read);
866 		if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
867 		if (err < B_OK) break;
868 	}
869 
870 	if (buffer != temp)
871 		free(buffer);
872 	return (err >= 0) ? B_OK : err;
873 }
874 
875 
876 //!	Encode into the native format
877 status_t
878 JP2Translator::Compress(BPositionIO* in, BPositionIO* out)
879 {
880 	using namespace conversion;
881 
882 	// Read info about bitmap
883 	TranslatorBitmap header;
884 	status_t err = in->Read(&header, sizeof(TranslatorBitmap));
885 	if (err < B_OK)
886 		return err;
887 	if (err < (int)sizeof(TranslatorBitmap))
888 		return B_ERROR;
889 
890 	// Grab dimension, color space, and size information from the stream
891 	BRect bounds;
892 	bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
893 	bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
894 	bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
895 	bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
896 
897 	int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
898 
899 	int width = bounds.IntegerWidth() + 1;
900 	int height = bounds.IntegerHeight() + 1;
901 
902 	// Function pointer to write function
903 	// It MUST point to proper function
904 	void (*converter)(jas_matrix_t** pixels, uchar* inscanline,
905 		int width) = write_rgba32;
906 
907 	// Default color info
908 	int out_color_space = JAS_CLRSPC_SRGB;
909 	int out_color_components = 3;
910 
911 	switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
912 		case B_GRAY1:
913 			if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) {
914 				converter = write_gray1_to_rgb24;
915 			} else {
916 				out_color_components = 1;
917 				out_color_space = JAS_CLRSPC_SGRAY;
918 				converter = write_gray1_to_gray;
919 			}
920 			break;
921 
922 		case B_CMAP8:
923 			converter = write_cmap8_to_rgb24;
924 			break;
925 
926 		case B_GRAY8:
927 			out_color_components = 1;
928 			out_color_space = JAS_CLRSPC_SGRAY;
929 			converter = write_gray;
930 			break;
931 
932 		case B_RGB15:
933 		case B_RGBA15:
934 			converter = write_rgb15_to_rgb24;
935 			break;
936 
937 		case B_RGB15_BIG:
938 		case B_RGBA15_BIG:
939 			converter = write_rgb15b_to_rgb24;
940 			break;
941 
942 		case B_RGB16:
943 			converter = write_rgb16_to_rgb24;
944 			break;
945 
946 		case B_RGB16_BIG:
947 			converter = write_rgb16b_to_rgb24;
948 			break;
949 
950 		case B_RGB24:
951 			converter = write_rgb24;
952 			break;
953 
954 		case B_RGB24_BIG:
955 			converter = write_rgb24b;
956 			break;
957 
958 		case B_RGB32:
959 			converter = write_rgb32_to_rgb24;
960 			break;
961 
962 		case B_RGB32_BIG:
963 			converter = write_rgb32b_to_rgb24;
964 			break;
965 
966 		case B_RGBA32:
967 		/*
968 			// In theory it should be possible to write 4 color components
969 			// to jp2, so it should be possible to have transparency.
970 			// Unfortunetly libjasper does not agree with that
971 			// For now i don't know how to modify it :(
972 
973 			out_color_components = 4;
974 			converter = write_rgba32;
975 		*/
976 			converter = write_rgb32_to_rgb24;
977 			break;
978 
979 		case B_RGBA32_BIG:
980 		/*
981 			// In theory it should be possible to write 4 color components
982 			// to jp2, so it should be possible to have transparency.
983 			// Unfortunetly libjasper does not agree with that
984 			// For now i don't know how to modify it :(
985 
986 			out_color_components = 4;
987 			converter = write_rgba32b;
988 		*/
989 			converter = write_rgb32b_to_rgb24;
990 			break;
991 
992 		default:
993 			syslog(LOG_ERR, "Unknown color space.\n");
994 			return B_ERROR;
995 	}
996 
997 	jas_image_t* image;
998 	jas_stream_t* outs;
999 	jas_matrix_t* pixels[4];
1000 	jas_image_cmptparm_t component_info[4];
1001 
1002 	if (jas_init())
1003 		return B_ERROR;
1004 
1005 	if (!(outs = jas_stream_positionIOopen(out)))
1006 		return B_ERROR;
1007 
1008 	int32 i = 0;
1009 	for (i = 0; i < (long)out_color_components; i++) {
1010 		(void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t));
1011 		component_info[i].hstep = 1;
1012 		component_info[i].vstep = 1;
1013 		component_info[i].width = (unsigned int)width;
1014 		component_info[i].height = (unsigned int)height;
1015 		component_info[i].prec = (unsigned int)8;
1016 	}
1017 
1018 	image = jas_image_create((short)out_color_components, component_info,
1019 		out_color_space);
1020 	if (image == (jas_image_t *)NULL)
1021 		return Error(outs, NULL, NULL, 0, NULL, B_ERROR);
1022 
1023 	uchar *in_scanline = (uchar*) malloc(in_row_bytes);
1024 	if (in_scanline == NULL)
1025 		return Error(outs, image, NULL, 0, NULL, B_ERROR);
1026 
1027 	for (i = 0; i < (long)out_color_components; i++) {
1028 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1029 		if (pixels[i] == (jas_matrix_t *)NULL)
1030 			return Error(outs, image, pixels, i+1, in_scanline, B_ERROR);
1031 	}
1032 
1033 	int32 y = 0;
1034 	for (y = 0; y < (long)height; y++) {
1035 		err = in->Read(in_scanline, in_row_bytes);
1036 		if (err < in_row_bytes) {
1037 			return (err < B_OK) ? Error(outs, image, pixels,
1038 					out_color_components, in_scanline, err)
1039 				: Error(outs, image, pixels, out_color_components, in_scanline,
1040 					B_ERROR);
1041 		}
1042 
1043 		converter(pixels, in_scanline, width);
1044 
1045 		for (i = 0; i < (long)out_color_components; i++) {
1046 			(void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y,
1047 				(unsigned int)width, 1, pixels[i]);
1048 		}
1049 	}
1050 
1051 	char opts[16];
1052 	sprintf(opts, "rate=%1f",
1053 		(float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0);
1054 
1055 	if (jas_image_encode(image, outs, jas_image_strtofmt(
1056 			fSettings->SetGetBool(JP2_SET_JPC) ?
1057 				(char*)"jpc" : (char*)"jp2"), opts)) {
1058 		return Error(outs, image, pixels,
1059 			out_color_components, in_scanline, err);
1060 	}
1061 
1062 	free(in_scanline);
1063 
1064 	for (i = 0; i < (long)out_color_components; i++)
1065 		jas_matrix_destroy(pixels[i]);
1066 
1067 	jas_stream_close(outs);
1068 	jas_image_destroy(image);
1069 	jas_image_clearfmts();
1070 
1071 	return B_OK;
1072 }
1073 
1074 
1075 //!	Decode the native format
1076 status_t
1077 JP2Translator::Decompress(BPositionIO* in, BPositionIO* out)
1078 {
1079 	using namespace conversion;
1080 
1081 	jas_image_t* image;
1082 	jas_stream_t* ins;
1083 	jas_matrix_t* pixels[4];
1084 
1085 	if (jas_init())
1086 		return B_ERROR;
1087 
1088 	if (!(ins = jas_stream_positionIOopen(in)))
1089 		return B_ERROR;
1090 
1091 	if (!(image = jas_image_decode(ins, -1, 0)))
1092 		return Error(ins, NULL, NULL, 0, NULL, B_ERROR);
1093 
1094 	// Default color info
1095 	color_space out_color_space;
1096 	int out_color_components;
1097 	int	in_color_components = jas_image_numcmpts(image);
1098 
1099 	// Function pointer to read function
1100 	// It MUST point to proper function
1101 	void (*converter)(jas_matrix_t** pixels, uchar* outscanline,
1102 		int width) = NULL;
1103 
1104 	switch (jas_clrspc_fam(jas_image_clrspc(image))) {
1105 		case JAS_CLRSPC_FAM_RGB:
1106 			out_color_components = 4;
1107 			if (in_color_components == 3) {
1108 				out_color_space = B_RGB32;
1109 				converter = read_rgb24_to_rgb32;
1110 			} else if (in_color_components == 4) {
1111 				out_color_space = B_RGBA32;
1112 				converter = read_rgba32;
1113 			} else {
1114 				syslog(LOG_ERR, "Other than RGB with 3 or 4 color "
1115 					"components not implemented.\n");
1116 				return Error(ins, image, NULL, 0, NULL, B_ERROR);
1117 			}
1118 			break;
1119 		case JAS_CLRSPC_FAM_GRAY:
1120 			if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) {
1121 				out_color_space = B_RGB32;
1122 				out_color_components = 4;
1123 				converter = read_gray_to_rgb32;
1124 			} else {
1125 				out_color_space = B_GRAY8;
1126 				out_color_components = 1;
1127 				converter = read_gray;
1128 			}
1129 			break;
1130 		case JAS_CLRSPC_FAM_YCBCR:
1131 			syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n");
1132 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1133 			break;
1134 		case JAS_CLRSPC_UNKNOWN:
1135 		default:
1136 			syslog(LOG_ERR, "Color space unknown. \n");
1137 			return Error(ins, image, NULL, 0, NULL, B_ERROR);
1138 			break;
1139 	}
1140 
1141 	float width = (float)jas_image_width(image);
1142 	float height = (float)jas_image_height(image);
1143 
1144 	// Bytes count in one line of image (scanline)
1145 	int64 out_row_bytes = (int32)width * out_color_components;
1146 		// NOTE: things will go wrong if "out_row_bytes" wouldn't fit into 32 bits
1147 
1148 	// !!! Initialize this bounds rect to the size of your image
1149 	BRect bounds(0, 0, width - 1, height - 1);
1150 
1151 
1152 	// Fill out the B_TRANSLATOR_BITMAP's header
1153 	TranslatorBitmap header;
1154 	header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
1155 	header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
1156 	header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
1157 	header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
1158 	header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
1159 	header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
1160 	header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes);
1161 	header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height));
1162 
1163 	// Write out the header
1164 	status_t err = out->Write(&header, sizeof(TranslatorBitmap));
1165 	if (err < B_OK)
1166 		return Error(ins, image, NULL, 0, NULL, err);
1167 	if (err < (int)sizeof(TranslatorBitmap))
1168 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1169 
1170 	uchar *out_scanline = (uchar*) malloc(out_row_bytes);
1171 	if (out_scanline == NULL)
1172 		return Error(ins, image, NULL, 0, NULL, B_ERROR);
1173 
1174 	int32 i = 0;
1175 	for (i = 0; i < (long)in_color_components; i++) {
1176 		pixels[i] = jas_matrix_create(1, (unsigned int)width);
1177 		if (pixels[i] == (jas_matrix_t *)NULL)
1178 			return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR);
1179 	}
1180 
1181 	int32 y = 0;
1182 	for (y = 0; y < (long)height; y++) {
1183 		for (i = 0; i < (long)in_color_components; i++) {
1184 			(void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y,
1185 				(unsigned int)width, 1, pixels[i]);
1186 		}
1187 
1188 		converter(pixels, out_scanline, (int32)width);
1189 
1190 		err = out->Write(out_scanline, out_row_bytes);
1191 		if (err < out_row_bytes) {
1192 			return (err < B_OK) ? Error(ins, image, pixels, in_color_components,
1193 				out_scanline, err)
1194 				: Error(ins, image, pixels, in_color_components, out_scanline,
1195 					B_ERROR);
1196 		}
1197 	}
1198 
1199 	free(out_scanline);
1200 
1201 	for (i = 0; i < (long)in_color_components; i++)
1202 		jas_matrix_destroy(pixels[i]);
1203 
1204 	jas_stream_close(ins);
1205 	jas_image_destroy(image);
1206 	jas_image_clearfmts();
1207 
1208 	return B_OK;
1209 }
1210 
1211 
1212 /*! searches in both inputFormats & outputFormats */
1213 status_t
1214 JP2Translator::PopulateInfoFromFormat(translator_info* info,
1215 	uint32 formatType, translator_id id)
1216 {
1217 	int32 formatCount;
1218 	const translation_format* formats = OutputFormats(&formatCount);
1219 
1220 	for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) {
1221 		if (PopulateInfoFromFormat(info, formatType,
1222 			formats, formatCount) == B_OK) {
1223 			info->translator = id;
1224 			return B_OK;
1225 		}
1226 	}
1227 
1228 	return B_ERROR;
1229 }
1230 
1231 
1232 status_t
1233 JP2Translator::PopulateInfoFromFormat(translator_info* info,
1234 	uint32 formatType, const translation_format* formats, int32 formatCount)
1235 {
1236 	for (int i = 0; i < formatCount; i++) {
1237 		if (formats[i].type == formatType) {
1238 			info->type = formatType;
1239 			info->group = formats[i].group;
1240 			info->quality = formats[i].quality;
1241 			info->capability = formats[i].capability;
1242 			if (strcmp(formats[i].name, B_TRANSLATOR_BITMAP_DESCRIPTION)
1243 				== 0) {
1244 				strlcpy(info->name,
1245 					B_TRANSLATE(B_TRANSLATOR_BITMAP_DESCRIPTION),
1246 					sizeof(info->name));
1247 			} else {
1248 				strlcpy(info->name, formats[i].name, sizeof(info->name));
1249 			}
1250 			strlcpy(info->MIME, formats[i].MIME, sizeof(info->MIME));
1251 			return B_OK;
1252 		}
1253 	}
1254 
1255 	return B_ERROR;
1256 }
1257 
1258 
1259 /*!
1260 	Frees jpeg alocated memory
1261 	Returns given error (B_ERROR by default)
1262 */
1263 status_t
1264 Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels,
1265 	int32 pixels_count, uchar* scanline, status_t error)
1266 {
1267 	if (pixels) {
1268 		int32 i;
1269 		for (i = 0; i < (long)pixels_count; i++) {
1270 			if (pixels[i] != NULL)
1271 				jas_matrix_destroy(pixels[i]);
1272 		}
1273 	}
1274 	if (stream)
1275 		jas_stream_close(stream);
1276 	if (image)
1277 		jas_image_destroy(image);
1278 
1279 	jas_image_clearfmts();
1280 	free(scanline);
1281 
1282 	return error;
1283 }
1284 
1285 
1286 //	#pragma mark -
1287 
1288 BTranslator*
1289 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
1290 {
1291 	if (!n)
1292 		return new JP2Translator();
1293 
1294 	return NULL;
1295 }
1296 
1297 
1298 int
1299 main()
1300 {
1301 	BApplication app("application/x-vnd.Haiku-JPEG2000Translator");
1302 	JP2Translator* translator = new JP2Translator();
1303 	if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK)
1304 		app.Run();
1305 
1306 	return 0;
1307 }
1308 
1309