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