4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcsignals.h"
27 #include "mwindow.inc"
29 #include "mainerror.h"
34 /* Known image types. */
35 #define TGA_TYPE_MAPPED 1
36 #define TGA_TYPE_COLOR 2
37 #define TGA_TYPE_GRAY 3
39 /* Only known compression is RLE */
40 #define TGA_COMP_NONE 0
41 #define TGA_COMP_RLE 1
44 FileTGA::FileTGA(Asset *asset, File *file)
45 : FileList(asset, file, "TGALIST", ".tga", FILE_TGA, FILE_TGA_LIST)
55 int FileTGA::check_sig(Asset *asset)
59 // Test file extension
61 char *ext = strrchr(asset->path, '.');
66 if(!strncasecmp(ext, ".tga", 4)) result = 1;
76 if(!(stream = fopen(asset->path, "rb")))
84 (void)fread(test, 16, 1, stream);
86 if(test[0] == 'T' && test[1] == 'G' && test[2] == 'A' &&
87 test[3] == 'L' && test[4] == 'I' && test[5] == 'S' &&
100 void FileTGA::get_parameters(BC_WindowBase *parent_window,
101 Asset *asset, BC_WindowBase* &format_window,
102 int audio_options, int video_options, EDL *edl)
106 TGAConfigVideo *window = new TGAConfigVideo(parent_window, asset);
107 format_window = window;
108 window->create_objects();
109 window->run_window();
116 N_("RGBA compressed")
117 N_("RGB uncompressed")
118 N_("RGBA uncompressed")
121 #define TGA_RGB_RLE "rle "
122 #define TGA_RGBA_RLE "rlea"
123 #define TGA_RGB "raw "
124 #define TGA_RGBA "rawa"
126 #define TGA_RGB_RLE_NAME "RGB compressed"
127 #define TGA_RGBA_RLE_NAME "RGBA compressed"
128 #define TGA_RGB_NAME "RGB uncompressed"
129 #define TGA_RGBA_NAME "RGBA uncompressed"
131 const char* FileTGA::compression_to_str(const char *compression)
133 if(!strcasecmp(compression, TGA_RGB_RLE)) return _(TGA_RGB_RLE_NAME);
134 if(!strcasecmp(compression, TGA_RGBA_RLE)) return _(TGA_RGBA_RLE_NAME);
135 if(!strcasecmp(compression, TGA_RGB)) return _(TGA_RGB_NAME);
136 if(!strcasecmp(compression, TGA_RGBA)) return _(TGA_RGBA_NAME);
140 const char* FileTGA::str_to_compression(const char *string)
142 if(!strcasecmp(compression_to_str(TGA_RGB_RLE), string)) return TGA_RGB_RLE;
143 if(!strcasecmp(compression_to_str(TGA_RGBA_RLE), string)) return TGA_RGBA_RLE;
144 if(!strcasecmp(compression_to_str(TGA_RGB), string)) return TGA_RGB;
145 if(!strcasecmp(compression_to_str(TGA_RGBA), string)) return TGA_RGBA;
149 int FileTGA::can_copy_from(Asset *asset, int64_t position)
151 if(asset->format == FILE_TGA_LIST ||
152 asset->format == FILE_TGA)
159 int FileTGA::colormodel_supported(int colormodel)
164 int FileTGA::get_best_colormodel(Asset *asset, int driver)
166 if(!strcasecmp(asset->vcodec, TGA_RGB_RLE) ||
167 !strcasecmp(asset->vcodec, TGA_RGB)) return BC_RGB888;
168 if(!strcasecmp(asset->vcodec, TGA_RGBA_RLE) ||
169 !strcasecmp(asset->vcodec, TGA_RGBA)) return BC_RGBA8888;
173 int FileTGA::read_frame(VFrame *frame, VFrame *data)
175 read_tga(asset, frame, data, temp);
179 int FileTGA::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
181 TGAUnit *tga_unit = (TGAUnit*)unit;
183 write_tga(asset, frame, data, tga_unit->temp);
187 FrameWriterUnit* FileTGA::new_writer_unit(FrameWriter *writer)
189 return new TGAUnit(this, writer);
192 int64_t FileTGA::get_memory_usage()
194 int64_t result = FileList::get_memory_usage();
195 if(temp) result += temp->get_data_size();
206 #define FOOTERSIZE 26
207 #define HEADERSIZE 18
208 int FileTGA::read_frame_header(char *path)
212 //printf("FileTGA::read_frame_header 1\n");
215 if(!(stream = fopen(path, "rb")))
217 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
221 unsigned char header[HEADERSIZE];
222 (void)fread(header, HEADERSIZE, 1, stream);
225 asset->width = header[12] | (header[13] << 8);
226 asset->height = header[14] | (header[15] << 8);
227 int bpp = header[16];
228 int rle = header[2] & 0x8;
233 strcpy(asset->vcodec, TGA_RGBA_RLE);
235 strcpy(asset->vcodec, TGA_RGBA);
239 strcpy(asset->vcodec, TGA_RGB_RLE);
241 strcpy(asset->vcodec, TGA_RGB);
244 //printf("FileTGA::read_frame_header 2 %d %d\n", asset->width, asset->height);
249 void FileTGA::read_tga(Asset *asset, VFrame *frame, VFrame *data, VFrame* &temp)
252 int64_t file_offset = 0;
254 // unsigned char *footer = data->get_data() +
255 // data->get_compressed_size() - FOOTERSIZE;
256 unsigned char *header = data->get_data();
257 file_offset += HEADERSIZE;
260 int image_compression = 0;
264 image_type = TGA_TYPE_MAPPED;
265 image_compression = TGA_COMP_NONE;
268 image_type = TGA_TYPE_COLOR;
269 image_compression = TGA_COMP_NONE;
272 image_type = TGA_TYPE_GRAY;
273 image_compression = TGA_COMP_NONE;
276 image_type = TGA_TYPE_MAPPED;
277 image_compression = TGA_COMP_RLE;
280 image_type = TGA_TYPE_COLOR;
281 image_compression = TGA_COMP_RLE;
284 image_type = TGA_TYPE_GRAY;
285 image_compression = TGA_COMP_RLE;
289 int idlength = header[0];
290 int colormaptype = header[1];
291 //int colormapindex = header[3] + header[4] * 256;
292 int colormaplength = header[5] + header[6] * 256;
293 int colormapsize = header[7];
294 //int xorigin = header[8] + header[9] * 256;
295 //int yorigin = header[10] + header[11] * 256;
296 int width = header[12] + header[13] * 256;
297 int height = header[14] + header[15] * 256;
298 int bpp = header[16];
299 int bytes = (bpp + 7) / 8;
300 int alphabits = header[17] & 0x0f;
301 int fliphoriz = (header[17] & 0x10) ? 1 : 0;
302 int flipvert = (header[17] & 0x20) ? 0 : 1;
303 int data_size = data->get_compressed_size();
305 if(idlength) file_offset += idlength;
308 unsigned char *tga_cmap;
309 unsigned char colormap[4 * 256];
311 if(colormaptype == 1)
313 int cmap_bytes = (colormapsize + 7) / 8;
314 tga_cmap = data->get_data() + file_offset;
315 file_offset += colormaplength * cmap_bytes;
320 bgr2rgb(colormap, tga_cmap, colormaplength, cmap_bytes, 1);
323 bgr2rgb(colormap, tga_cmap, colormaplength, cmap_bytes, 0);
326 upsample(colormap, tga_cmap, colormaplength, cmap_bytes);
331 int source_cmodel = BC_RGB888;
335 source_cmodel = BC_RGBA8888;
338 source_cmodel = BC_RGB888;
343 VFrame *output_frame;
344 if(frame->get_color_model() == source_cmodel)
346 output_frame = frame;
350 if(temp && temp->get_color_model() != source_cmodel)
358 temp = new VFrame(width, height, source_cmodel, 0);
365 for(int i = height - 1; i >= 0; i--)
367 read_line(output_frame->get_rows()[i],
382 for(int i = 0; i < height; i++)
384 read_line(output_frame->get_rows()[i],
398 if(output_frame != frame)
400 BC_CModels::transfer(frame->get_rows(), output_frame->get_rows(),
401 frame->get_y(), frame->get_u(), frame->get_v(),
402 output_frame->get_y(), output_frame->get_u(), output_frame->get_v(),
404 0, 0, frame->get_w(), frame->get_h(),
405 output_frame->get_color_model(), frame->get_color_model(),
406 0, width, frame->get_w());
410 void FileTGA::write_tga(Asset *asset, VFrame *frame, VFrame *data, VFrame* &temp)
412 unsigned char header[18];
413 //unsigned char footer[26];
414 int64_t file_offset = 0;
417 int dest_cmodel = BC_RGB888;
419 //printf("FileTGA::write_tga 1\n");
423 if(!strcasecmp(asset->vcodec, TGA_RGBA_RLE))
428 header[16] = 32; /* bpp */
429 header[17] = 0x28; /* alpha + orientation */
430 dest_cmodel = BC_RGBA8888;
433 if(!strcasecmp(asset->vcodec, TGA_RGBA))
438 header[16] = 32; /* bpp */
439 header[17] = 0x28; /* alpha + orientation */
440 dest_cmodel = BC_RGBA8888;
443 if(!strcasecmp(asset->vcodec, TGA_RGB_RLE))
448 header[16] = 24; /* bpp */
449 header[17] = 0x20; /* alpha + orientation */
450 dest_cmodel = BC_RGB888;
457 header[16] = 24; /* bpp */
458 header[17] = 0x20; /* alpha + orientation */
459 dest_cmodel = BC_RGB888;
461 header[3] = header[4] = header[5] = header[6] = header[7] = 0;
462 //printf("FileTGA::write_tga 1\n");
465 if(frame->get_color_model() == dest_cmodel)
471 if(temp && temp->get_color_model() != dest_cmodel)
479 temp = new VFrame(0, -1, frame->get_w(), frame->get_h(), dest_cmodel, -1);
483 BC_CModels::transfer(input_frame->get_rows(), frame->get_rows(),
484 input_frame->get_y(), input_frame->get_u(), input_frame->get_v(),
485 frame->get_y(), frame->get_u(), frame->get_v(),
486 0, 0, frame->get_w(), frame->get_h(),
487 0, 0, frame->get_w(), frame->get_h(),
488 frame->get_color_model(), input_frame->get_color_model(),
489 0, frame->get_w(), frame->get_w());
491 //printf("FileTGA::write_tga 1\n");
495 header[8] = header[9] = 0;
496 header[10] = header[11] = 0;
498 header[12] = input_frame->get_w() % 256;
499 header[13] = input_frame->get_w() / 256;
501 header[14] = input_frame->get_h() % 256;
502 header[15] = input_frame->get_h() / 256;
503 //printf("FileTGA::write_tga 1\n");
505 write_data(header, data, file_offset, sizeof(header));
506 //printf("FileTGA::write_tga 1\n");
508 unsigned char *output = new unsigned char[out_bpp * input_frame->get_w()];
509 //printf("FileTGA::write_tga 1\n");
510 for(int i = 0; i < input_frame->get_h(); i++)
512 //printf("FileTGA::write_tga 2\n");
513 bgr2rgb(output, input_frame->get_rows()[i], input_frame->get_w(), out_bpp, (out_bpp == 4));
514 //printf("FileTGA::write_tga 3\n");
518 //printf("FileTGA::write_tga 4\n");
520 input_frame->get_w(),
524 //printf("FileTGA::write_tga 5\n");
528 //printf("FileTGA::write_tga 6\n");
532 input_frame->get_w() * out_bpp);
533 //printf("FileTGA::write_tga 7\n");
536 //printf("FileTGA::write_tga 8\n");
538 //printf("FileTGA::write_tga 9\n");
541 void FileTGA::write_data(unsigned char *buffer,
543 int64_t &file_offset,
546 //printf("FileTGA::write_data 1 %d\n", len);
547 if(data->get_compressed_allocated() <= data->get_compressed_size() + len)
549 data->allocate_compressed_data((data->get_compressed_size() + len) * 2);
551 //printf("FileTGA::write_data 1 %d\n", len);
553 bcopy(buffer, data->get_data() + file_offset, len);
554 //printf("FileTGA::write_data 1 %d\n", len);
556 //printf("FileTGA::write_data 1 %d\n", len);
557 data->set_compressed_size(file_offset);
558 //printf("FileTGA::write_data 2 %d\n", len);
561 void FileTGA::read_line(unsigned char *row, unsigned char *data,
562 int64_t &file_offset, int image_type, int bpp, int image_compression,
563 int bytes, int width, int fliphoriz, int alphabits, int data_size)
565 if(file_offset >= data_size) return;
566 if(image_compression == TGA_COMP_RLE)
568 rle_read(row, data, file_offset, bytes, width);
572 if(file_offset + bytes * width <= data_size)
573 bcopy(data + file_offset, row, bytes * width);
574 file_offset += bytes * width;
579 flip_line(row, bytes, width);
582 if(image_type == TGA_TYPE_COLOR)
586 upsample(row, row, width, bytes);
590 bgr2rgb(row, row, width, bytes, alphabits);
599 void FileTGA::flip_line(unsigned char *row, int bytes, int width)
604 alt = row + (bytes * (width - 1));
606 for (x = 0; x * 2 <= width; x++) {
607 for(s = 0; s < bytes; ++s) {
618 void FileTGA::rle_read(unsigned char *row,
620 int64_t &file_offset,
626 unsigned char sample[4];
629 for(int x = 0; x < width; x++)
631 if(repeat == 0 && direct == 0)
633 head = data[file_offset++];
642 bcopy(data + file_offset, sample, bytes);
643 file_offset += bytes;
653 for(int k = 0; k < bytes; k++)
662 bcopy(data + file_offset, row, bytes);
663 file_offset += bytes;
672 void FileTGA::rle_write(unsigned char *buffer,
676 int64_t &file_offset)
680 unsigned char *from = buffer;
681 unsigned char output;
684 for(x = 1; x < width; ++x)
686 /* next pixel is different */
687 if(memcmp(buffer, buffer + bytes, bytes))
691 output = 128 + repeat;
692 write_data(&output, frame, file_offset, 1);
693 write_data(from, frame, file_offset, bytes);
694 from = buffer + bytes;
704 /* next pixel is the same */
709 write_data(&output, frame, file_offset, 1);
710 write_data(from, frame, file_offset, bytes * direct);
724 write_data(&output, frame, file_offset, 1);
725 write_data(from, frame, file_offset, bytes);
726 from = buffer + bytes;
734 write_data(&output, frame, file_offset, 1);
735 write_data(from, frame, file_offset, direct * bytes);
736 from = buffer + bytes;
746 output = 128 + repeat;
747 write_data(&output, frame, file_offset, 1);
748 write_data(from, frame, file_offset, bytes);
753 write_data(&output, frame, file_offset, 1);
754 write_data(from, frame, file_offset, bytes * (direct + 1));
759 void FileTGA::bgr2rgb(unsigned char *dest, unsigned char *src,
760 int width, int bytes, int alpha)
763 unsigned char r, g, b;
766 for(x = 0; x < width; x++) {
767 r = src[2]; g = src[1]; b = src[0];
768 *(dest++) = r; *(dest++) = g; *(dest++) = b;
769 *(dest++) = src[3]; src += bytes;
773 for(x = 0; x < width; x++) {
774 r = src[2]; g = src[1]; b = src[0];
775 *(dest++) = r; *(dest++) = g; *(dest++) = b;
781 void FileTGA::upsample(unsigned char *dest,
788 dest += (width - 1) * 3;
789 src += (width - 1) * bytes;
790 for(x = width - 1; x >= 0; x--) {
791 dest[0] = ((src[1] << 1) & 0xf8);
792 dest[0] += (dest[0] >> 5);
794 dest[1] = ((src[0] & 0xe0) >> 2) + ((src[1] & 0x03) << 6);
795 dest[1] += (dest[1] >> 5);
797 dest[2] = ((src[0] << 3) & 0xf8);
798 dest[2] += (dest[2] >> 5);
806 TGAUnit::TGAUnit(FileTGA *file, FrameWriter *writer)
807 : FrameWriterUnit(writer)
815 if(temp) delete temp;
819 TGAConfigVideo::TGAConfigVideo(BC_WindowBase *gui, Asset *asset)
820 : BC_Window(_(PROGRAM_NAME ": Video Compression"),
821 gui->get_abs_cursor_x(1), gui->get_abs_cursor_y(1),
827 compression_items.append(new BC_ListBoxItem(FileTGA::compression_to_str(TGA_RGB_RLE)));
828 compression_items.append(new BC_ListBoxItem(FileTGA::compression_to_str(TGA_RGBA_RLE)));
829 compression_items.append(new BC_ListBoxItem(FileTGA::compression_to_str(TGA_RGB)));
830 compression_items.append(new BC_ListBoxItem(FileTGA::compression_to_str(TGA_RGBA)));
831 // *** CONTEXT_HELP ***
832 context_help_set_keyword("Single File Rendering");
835 TGAConfigVideo::~TGAConfigVideo()
837 compression_items.remove_all_objects();
840 void TGAConfigVideo::create_objects()
842 lock_window("TGAConfigVideo::create_objects");
843 int x = xS(10), y = yS(10);
845 add_subwindow(new BC_Title(x, y, _("Compression:")));
846 TGACompression *textbox = new TGACompression(this,
847 x + xS(110), y, asset, &compression_items);
848 textbox->create_objects();
849 add_subwindow(new BC_OKButton(this));
854 int TGAConfigVideo::close_event()
861 TGACompression::TGACompression(TGAConfigVideo *gui, int x, int y,
862 Asset *asset, ArrayList<BC_ListBoxItem*> *compression_items)
863 : BC_PopupTextBox(gui, compression_items,
864 FileTGA::compression_to_str(gui->asset->vcodec),
865 x, y, xS(200), yS(200))
869 int TGACompression::handle_event()
871 strcpy(asset->vcodec, FileTGA::str_to_compression(get_text()));