Added support for the TGA file format in the codec
authorFrancois-Olivier Devaux <fodevaux@users.noreply.github.com>
Mon, 20 Aug 2007 15:20:42 +0000 (15:20 +0000)
committerFrancois-Olivier Devaux <fodevaux@users.noreply.github.com>
Mon, 20 Aug 2007 15:20:42 +0000 (15:20 +0000)
ChangeLog
codec/compat/getopt.c
codec/convert.c
codec/convert.h
codec/image_to_j2k.c
codec/j2k_to_image.c

index a54be224c6f14a69b529cb4ae12129d89fac89b9..5832d56336d5f335def65559d7b424ddd228b3d6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,9 @@ What's New for OpenJPEG
 ! : changed
 + : added
 
+August 20, 2008
++ [FOD] Added support for the TGA file format in the codec
+
 August 08, 2008
 * [Parvatha] Fixed the DCinema filesize allocation. It now includes the SOT marker size
 
index 1491bf039a768a55f8a2ad511f9e89a1bfd99e27..23270e6af14fbb2412e0bb8848a0bbe0d19617de 100644 (file)
@@ -251,7 +251,7 @@ found:
                
                }// end of single character
        }//end '-'
-       fprintf(stderr,"Invalid option %s\n");
+       fprintf(stderr,"Invalid option\n");
        ++optind;
        return (BADCH);;
 }//end function
index 81b34dc99cf4a7e533bbac97ccc546a3c4388fe9..d074909fdff10325876e122c4fc34a5478d54f65 100644 (file)
@@ -67,6 +67,300 @@ static int int_ceildiv(int a, int b) {
        return (a + b - 1) / b;
 }
 
+
+/* -->> -->> -->> -->>
+
+  TGA IMAGE FORMAT
+
+ <<-- <<-- <<-- <<-- */
+
+// TGA header definition.
+#pragma pack(push,1) // Pack structure byte aligned
+typedef struct tga_header
+{                           
+    uint8   id_length;              /* Image id field length    */
+    uint8   colour_map_type;        /* Colour map type          */
+    uint8   image_type;             /* Image type               */
+    /*
+    ** Colour map specification
+    */
+    uint16  colour_map_index;       /* First entry index        */
+    uint16  colour_map_length;      /* Colour map length        */
+    uint8   colour_map_entry_size;  /* Colour map entry size    */
+    /*
+    ** Image specification
+    */
+    uint16  x_origin;               /* x origin of image        */
+    uint16  y_origin;               /* u origin of image        */
+    uint16  image_width;            /* Image width              */
+    uint16  image_height;           /* Image height             */
+    uint8   pixel_depth;            /* Pixel depth              */
+    uint8   image_desc;             /* Image descriptor         */
+} tga_header;
+#pragma pack(pop) // Return to normal structure packing alignment.
+
+int tga_readheader(FILE *fp, int *bits_per_pixel, int *width, int *height, int *flip_image)
+{
+       int palette_size;
+       tga_header tga ;
+
+       if (!bits_per_pixel || !width || !height || !flip_image)
+               return 0;
+       
+       // Read TGA header
+       fread((uint8*)&tga, sizeof(tga_header), 1, fp);
+
+       *bits_per_pixel = tga.pixel_depth;
+       
+       *width  = tga.image_width;
+       *height = tga.image_height ;
+
+       // Ignore tga identifier, if present ...
+       if (tga.id_length)
+       {
+               uint8 *id = (uint8 *) malloc(tga.id_length);
+               fread(id, tga.id_length, 1, fp);
+               free(id);  
+       }
+
+       // Test for compressed formats ... not yet supported ...
+       // Note :-  9 - RLE encoded palettized.
+       //                 10 - RLE encoded RGB.
+       if (tga.image_type > 8)
+       {
+               fprintf(stderr, "Sorry, compressed tga files are not currently supported.\n");
+               return 0 ;
+       }
+
+       *flip_image = !(tga.image_desc & 32);
+
+       // Palettized formats are not yet supported, skip over the palette, if present ... 
+       palette_size = tga.colour_map_length * (tga.colour_map_entry_size/8);
+       
+       if (palette_size>0)
+       {
+               fprintf(stderr, "File contains a palette - not yet supported.");
+               fseek(fp, palette_size, SEEK_CUR);
+       }
+       return 1;
+}
+
+int tga_writeheader(FILE *fp, int bits_per_pixel, int width, int height, bool flip_image)
+{
+       tga_header tga;
+
+       if (!bits_per_pixel || !width || !height)
+               return 0;
+
+       memset(&tga, 0, sizeof(tga_header));
+
+       tga.pixel_depth = bits_per_pixel;
+       tga.image_width  = width;
+       tga.image_height = height;
+       tga.image_type = 2; // Uncompressed.
+       tga.image_desc = 8; // 8 bits per component.
+
+       if (flip_image)
+               tga.image_desc |= 32;
+
+       // Write TGA header
+       fwrite((uint8*)&tga, sizeof(tga_header), 1, fp);
+
+       return 1;
+}
+
+opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) {
+       FILE *f;
+       opj_image_t *image;
+       uint32 image_width, image_height, pixel_bit_depth;
+       uint32 x, y;
+       int flip_image=0;
+       opj_image_cmptparm_t cmptparm[4];       /* maximum 4 components */
+       int numcomps;
+       OPJ_COLOR_SPACE color_space;
+       bool mono ;
+       bool save_alpha;
+       int subsampling_dx, subsampling_dy;
+       int i;  
+
+       f = fopen(filename, "rb");
+       if (!f) {
+               fprintf(stderr, "Failed to open %s for reading !!\n", filename);
+               return 0;
+       }
+
+       if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, &flip_image))
+               return NULL;
+
+       // We currently only support 24 & 32 bit tga's ...
+       if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32)))
+               return NULL;
+
+       /* initialize image components */   
+       memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
+
+       mono = (pixel_bit_depth == 8) || (pixel_bit_depth == 16);  // Mono with & without alpha.
+       save_alpha = (pixel_bit_depth == 16) || (pixel_bit_depth == 32); // Mono with alpha, or RGB with alpha
+
+       if (mono) {
+               color_space = CLRSPC_GRAY;
+               numcomps = save_alpha ? 2 : 1;
+       }       
+       else {
+               numcomps = save_alpha ? 4 : 3;
+               color_space = CLRSPC_SRGB;
+       }
+
+       subsampling_dx = parameters->subsampling_dx;
+       subsampling_dy = parameters->subsampling_dy;
+
+       for (i = 0; i < numcomps; i++) {
+               cmptparm[i].prec = 8;
+               cmptparm[i].bpp = 8;
+               cmptparm[i].sgnd = 0;
+               cmptparm[i].dx = subsampling_dx;
+               cmptparm[i].dy = subsampling_dy;
+               cmptparm[i].w = image_width;
+               cmptparm[i].h = image_height;
+       }
+
+       /* create the image */
+       image = opj_image_create(numcomps, &cmptparm[0], color_space);
+
+       if (!image)
+               return NULL;
+
+       /* set image offset and reference grid */
+       image->x0 = parameters->image_offset_x0;
+       image->y0 = parameters->image_offset_y0;
+       image->x1 =     !image->x0 ? (image_width - 1) * subsampling_dx + 1 : image->x0 + (image_width - 1) * subsampling_dx + 1;
+       image->y1 =     !image->y0 ? (image_height - 1) * subsampling_dy + 1 : image->y0 + (image_height - 1) * subsampling_dy + 1;
+
+       /* set image data */
+       for (y=0; y < image_height; y++) 
+       {
+               int index;
+
+               if (flip_image)
+                       index = (image_height-y-1)*image_width;
+               else
+                       index = y*image_width;
+
+               if (numcomps==3)
+               {
+                       for (x=0;x<image_width;x++) 
+                       {
+                               uint8 r,g,b;
+                               fread(&b, 1, 1, f);
+                               fread(&g, 1, 1, f);
+                               fread(&r, 1, 1, f);
+
+                               image->comps[0].data[index]=r;
+                               image->comps[1].data[index]=g;
+                               image->comps[2].data[index]=b;
+                               index++;
+                       }
+               }
+               else if (numcomps==4)
+               {
+                       for (x=0;x<image_width;x++) 
+                       {
+                               uint8 r,g,b,a;
+                               fread(&b, 1, 1, f);
+                               fread(&g, 1, 1, f);
+                               fread(&r, 1, 1, f);
+                               fread(&a, 1, 1, f);
+
+                               image->comps[0].data[index]=r;
+                               image->comps[1].data[index]=g;
+                               image->comps[2].data[index]=b;
+                               image->comps[3].data[index]=a;
+                               index++;
+                       }
+               }
+               else {
+                       fprintf(stderr, "Currently unsupported bit depth : %s\n", filename);
+               }
+       }       
+       return image;
+}
+
+int imagetotga(opj_image_t * image, const char *outfile) {
+       int width, height, bpp, x, y;
+       bool write_alpha;
+       int i;
+       uint32 alpha_channel;
+       float r,g,b,a;
+       uint8 value;
+       float scale;
+       FILE *fdest;
+
+       fdest = fopen(outfile, "wb");
+       if (!fdest) {
+               fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile);
+               return 1;
+       }
+
+       for (i = 0; i < image->numcomps-1; i++) {
+               if ((image->comps[0].dx != image->comps[i+1].dx) 
+                       ||(image->comps[0].dy != image->comps[i+1].dy) 
+                       ||(image->comps[0].prec != image->comps[i+1].prec))     {
+      fprintf(stderr, "Unable to create a tga file with such J2K image charateristics.");
+      return 1;
+   }
+       }
+
+       width  = int_ceildiv(image->x1-image->x0, image->comps[0].dx);
+       height = int_ceildiv(image->y1-image->y0, image->comps[0].dy);
+
+       // Mono with alpha, or RGB with alpha.
+       write_alpha = (image->numcomps==2) || (image->numcomps==4);   
+
+       // Write TGA header 
+       bpp = write_alpha ? 32 : 24;
+       if (!tga_writeheader(fdest, bpp, width, height, true))
+               return 1;
+
+       alpha_channel = image->numcomps-1; 
+
+       scale = 255.0f / (float)((1<<image->comps[0].prec)-1);
+
+       for (y=0; y < height; y++) {
+               uint32 index=y*width;
+
+               for (x=0; x < width; x++, index++)      {
+                       r = (float)(image->comps[0].data[index]);
+
+                       if (image->numcomps>2) {
+                               g = (float)(image->comps[1].data[index]);
+                               b = (float)(image->comps[2].data[index]);
+                       }
+                       else  {// Greyscale ...
+                               g = r;
+                               b = r;
+                       }
+
+                       // TGA format writes BGR ...
+                       value = (uint8)(b*scale);
+                       fwrite(&value,1,1,fdest);
+
+                       value = (uint8)(g*scale);
+                       fwrite(&value,1,1,fdest);
+
+                       value = (uint8)(r*scale);
+                       fwrite(&value,1,1,fdest);
+
+                       if (write_alpha) {
+                               a = (float)(image->comps[alpha_channel].data[index]);
+                               value = (uint8)(a*scale);
+                               fwrite(&value,1,1,fdest);
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /* -->> -->> -->> -->>
 
   BMP IMAGE FORMAT
index b2bc16de3984e606d3ae241e4f896fd88c46cefa..98611c66b4f1a08e99d1f46d8f8108aac83c3e12 100644 (file)
@@ -47,8 +47,12 @@ typedef struct raw_cparameters {
        /*@}*/
 } raw_cparameters_t;
 
-opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters);
+/* TGA conversion */
+opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters);
+int imagetotga(opj_image_t * image, const char *outfile);
 
+/* BMP conversion */
+opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters);
 int imagetobmp(opj_image_t *image, const char *outfile);
 
 /* TIFF to image conversion*/
@@ -61,15 +65,13 @@ Load a single image component encoded in PGX file format
 @return Returns a greyscale image if successful, returns NULL otherwise
 */
 opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters);
-
 int imagetopgx(opj_image_t *image, const char *outfile);
 
 opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters);
-
 int imagetopnm(opj_image_t *image, const char *outfile);
 
+/* RAW conversion */
 int imagetoraw(opj_image_t * image, const char *outfile);
-
 opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp);
 
 #endif /* __J2K_CONVERT_H */
index 2e1468539204e220fa2438bf9697edad46873236..44747ee0a848501511368a0f22916b189c7296e7 100644 (file)
@@ -55,6 +55,7 @@
 #define YUV_DFMT 13
 #define TIF_DFMT 14
 #define RAW_DFMT 15
+#define TGA_DFMT 16
 
 /* ----------------------------------------------------------------------- */
 #define CINEMA_24_CS 1302083   /*Codestream length for 24fps*/
@@ -134,9 +135,9 @@ void encode_help_display() {
        fprintf(stdout,"-OutFor \n");
        fprintf(stdout,"    REQUIRED only if -ImgDir is used\n");
        fprintf(stdout,"          Need to specify only format without filename <BMP>  \n");
-       fprintf(stdout,"    Currently accepts PGM, PPM, PNM, PGX, BMP format\n");
+       fprintf(stdout,"    Currently accepts PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA formats\n");
        fprintf(stdout,"\n");
-       fprintf(stdout,"-i           : source file  (-i source.pnm also *.pgm, *.ppm, *.bmp, *.tif, *.raw) \n");
+       fprintf(stdout,"-i           : source file  (-i source.pnm also *.pgm, *.ppm, *.bmp, *.tif, *.raw, *.tga) \n");
        fprintf(stdout,"    When using this option -o must be used\n");
        fprintf(stdout,"\n");
        fprintf(stdout,"-o           : destination file (-o dest.j2k or .jp2) \n");
@@ -369,17 +370,17 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){
 int get_file_format(char *filename) {
        unsigned int i;
        static const char *extension[] = {
-    "pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "j2k", "jp2", "j2c"
+    "pgx", "pnm", "pgm", "ppm", "bmp", "tif", "raw", "tga", "j2k", "jp2", "j2c"
     };
        static const int format[] = {
-    PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT
+    PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT
     };
        char * ext = strrchr(filename, '.');
        if (ext == NULL)
                return -1;
        ext++;
        for(i = 0; i < sizeof(format)/sizeof(*format); i++) {
-               if(strnicmp(ext, extension[i], 3) == 0) {
+               if(_strnicmp(ext, extension[i], 3) == 0) {
                        return format[i];
                }
        }
@@ -583,11 +584,12 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters,
                                        case BMP_DFMT:
                                        case TIF_DFMT:
                                        case RAW_DFMT:
+                                       case TGA_DFMT:
                                                break;
                                        default:
                                                fprintf(stderr,
                                                        "!! Unrecognized format for infile : %s "
-              "[accept only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif or *.raw] !!\n\n", 
+              "[accept only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga] !!\n\n", 
                                                        infile);
                                                return 1;
                                }
@@ -1549,6 +1551,8 @@ int main(int argc, char **argv) {
                                break;
                        case RAW_DFMT:
                                break;
+                       case TGA_DFMT:
+                               break;
                        default:
                                fprintf(stderr,"skipping file...\n");
                                continue;                       
@@ -1597,6 +1601,14 @@ int main(int argc, char **argv) {
                                                return 1;
                                        }
                                break;
+
+                               case TGA_DFMT:
+                                       image = tgatoimage(parameters.infile, &parameters);
+                                       if (!image) {
+                                               fprintf(stderr, "Unable to load tga file\n");
+                                               return 1;
+                                       }
+                               break;
                }
                        /* Decide if MCT should be used */
                        parameters.tcp_mct = image->numcomps == 3 ? 1 : 0;
index 977b1d0385045cdbbd1dacbfd8807bd0dda86a5a..18f478aceeb1b06cf70ec6565284cf26468512b4 100644 (file)
@@ -55,6 +55,7 @@
 #define YUV_DFMT 13
 #define TIF_DFMT 14
 #define RAW_DFMT 15
+#define TGA_DFMT 16
 
 /* ----------------------------------------------------------------------- */
 
@@ -96,14 +97,14 @@ void decode_help_display() {
        fprintf(stdout,"  -OutFor \n");
        fprintf(stdout,"    REQUIRED only if -ImgDir is used\n");
        fprintf(stdout,"          Need to specify only format without filename <BMP>  \n");
-       fprintf(stdout,"    Currently accepts PGM, PPM, PNM, PGX, BMP, TIF and RAW formats\n");
+       fprintf(stdout,"    Currently accepts PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA formats\n");
        fprintf(stdout,"  -i <compressed file>\n");
        fprintf(stdout,"    REQUIRED only if an Input image directory not specified\n");
        fprintf(stdout,"    Currently accepts J2K-files, JP2-files and JPT-files. The file type\n");
        fprintf(stdout,"    is identified based on its suffix.\n");
        fprintf(stdout,"  -o <decompressed file>\n");
        fprintf(stdout,"    REQUIRED\n");
-       fprintf(stdout,"    Currently accepts PGM, PPM, PNM, PGX, BMP, TIF and RAW files\n");
+       fprintf(stdout,"    Currently accepts PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA files\n");
        fprintf(stdout,"    Binary data is written to the file (not ascii). If a PGX\n");
        fprintf(stdout,"    filename is given, there will be as many output files as there are\n");
        fprintf(stdout,"    components: an indice starting from 0 will then be appended to the\n");
@@ -182,15 +183,15 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){
 
 int get_file_format(char *filename) {
        unsigned int i;
-       static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "j2k", "jp2", "jpt", "j2c" };
-       static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT };
+       static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "j2k", "jp2", "jpt", "j2c" };
+       static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT };
        char * ext = strrchr(filename, '.');
        if (ext == NULL)
                return -1;
        ext++;
        if(ext) {
                for(i = 0; i < sizeof(format)/sizeof(*format); i++) {
-                       if(strnicmp(ext, extension[i], 3) == 0) {
+                       if(_strnicmp(ext, extension[i], 3) == 0) {
                                return format[i];
                        }
                }
@@ -276,9 +277,10 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
                                        case BMP_DFMT:
                                        case TIF_DFMT:
                                        case RAW_DFMT:
+                                       case TGA_DFMT:
                                                break;
                                        default:
-                                               fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif or *.raw]!! \n", outfile);
+                                               fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outfile);
                                                return 1;
                                }
                                strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1);
@@ -310,8 +312,11 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
                                        case RAW_DFMT:
                                                img_fol->out_format = "raw";
                                                break;
+                                       case TGA_DFMT:
+                                               img_fol->out_format = "raw";
+                                               break;
                                        default:
-                                               fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif or *.raw]!! \n");
+                                               fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outformat);
                                                return 1;
                                                break;
                                }
@@ -439,7 +444,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
                }
                if(img_fol->set_out_format == 0){
                        fprintf(stderr, "Error: When -ImgDir is used, -OutFor <FORMAT> must be used !!\n");
-                       fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW!!\n");
+                       fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA!!\n");
                        return 1;
                }
                if(!((parameters->outfile[0] == 0))){
@@ -450,7 +455,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
                if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) {
                        fprintf(stderr, "Error: One of the options -i or -ImgDir must be specified\n");
                        fprintf(stderr, "Error: When using -i, -o must be used\n");
-                       fprintf(stderr, "usage: image_to_j2k -i *.j2k/jp2/j2c -o *.pgm/ppm/pnm/pgx/bmp/tif/raw(+ options)\n");
+                       fprintf(stderr, "usage: image_to_j2k -i *.j2k/jp2/j2c -o *.pgm/ppm/pnm/pgx/bmp/tif/raw/tga(+ options)\n");
                        return 1;
                }
        }
@@ -722,6 +727,15 @@ int main(int argc, char **argv) {
                                fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile);
                        }
                        break;
+
+               case TGA_DFMT:                  /* TGA */
+                       if(imagetotga(image, parameters.outfile)){
+                               fprintf(stdout,"Error generating tga file. Outfile %s not generated\n",parameters.outfile);
+                       }
+                       else {
+                               fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile);
+                       }
+                       break;
                }
 
                /* free remaining structures */