예제 #1
0
Image* FW::importLodePngImage(InputStream& stream)
{
    // Read the entire input stream.

    Array<U8> dataBuffer;
    int blockSize = 4096;
    for (;;)
    {
        int pos = dataBuffer.getSize();
        dataBuffer.resize(pos + blockSize);
        int num = stream.read(dataBuffer.getPtr(pos), blockSize);
        if (num < blockSize)
        {
            dataBuffer.resize(pos + num);
            break;
        }
    }

    if (hasError())
        return NULL;

    // Decode image info.

    LodePNG::Decoder decoder;
    decoder.inspect(dataBuffer.getPtr(), dataBuffer.getSize());
    Vec2i size(decoder.getWidth(), decoder.getHeight());
    bool hasAlpha = (LodePNG_InfoColor_canHaveAlpha(&decoder.getInfoPng().color) != 0);

    if (decoder.hasError())
        setError("importLodePngImage(): LodePNG error %d!", decoder.getError());
    if (min(size) <= 0)
        setError("importLodePngImage(): Invalid image size!");
    if (hasError())
        return NULL;

    // Decode image data.

    int numBytes = size.x * size.y * ((hasAlpha) ? 4 : 3);
    std::vector<U8> pixelBuffer;
    pixelBuffer.reserve(numBytes);
    decoder.getInfoRaw().color.colorType = (hasAlpha) ? 6 : 2;
    decoder.decode(pixelBuffer, dataBuffer.getPtr(), dataBuffer.getSize());

    if (decoder.hasError())
        setError("importLodePngImage(): LodePNG error %d!", decoder.getError());
    if ((int)pixelBuffer.size() != numBytes)
        setError("importLodePngImage(): Incorrect amount of pixel data!");
    if (hasError())
        return NULL;

    // Create image.

    Image* image = new Image(size, (hasAlpha) ? ImageFormat::R8_G8_B8_A8 : ImageFormat::R8_G8_B8);
    image->getBuffer().set(&pixelBuffer[0], numBytes);
    return image;
}
예제 #2
0
bool ProceduralTexture::loadPNG(char *png_map)
{
	LodePNG::Decoder pngDecoder;
	std::vector<unsigned char> buffer;
	
	Logger::log("Loading png file %s..\n",png_map);
	
	LodePNG::loadFile(buffer,png_map);
	
	Logger::log("Calling PNG decoder..\n");
	pngDecoder.decode(image, buffer);
	
	Logger::log("Checking decoder state..\n");
	if(pngDecoder.hasError())
	{
		Logger::log("[loadTextureFromPng] Error %d\n", pngDecoder.getError());
		Logger::log(" while trying to load \'%s\'\n",png_map);
		return false;
	}
	
	width = pngDecoder.getWidth();
	height = pngDecoder.getHeight();
	
	Logger::log("PNG Decoder Info [ width: %d, height: %d ]..\n",width,height);
	
	Logger::log("image size: %d\n",image.size());
	
	Logger::log("isGreyScale: %s\n",pngDecoder.isGreyscaleType()?"true":"false");
	Logger::log("isAlphaType: %s\n",pngDecoder.isAlphaType()?"true":"false");
	Logger::log("Channels: %d\n",pngDecoder.getChannels());
	Logger::log("BPP: %d\n",pngDecoder.getBpp());
		
	return true;
}
예제 #3
0
bool C_TexturePNG::Load(S_Texture * texture, const char * filename)
{
      std::vector<unsigned char> buffer, image;
      LodePNG::loadFile(buffer, filename);
      LodePNG::Decoder decoder;
      decoder.decode(image, buffer);

      if(decoder.hasError())
        return false;

      texture->width = decoder.getWidth();
      texture->height = decoder.getHeight();
      texture->bpp = decoder.getBpp();
      texture->imageData = new GLubyte[image.size()];
      std::copy(image.begin(), image.end(), texture->imageData);
      texture->type = GL_RGBA;

      return true;
}
예제 #4
0
 //lodepng용 추가 함수
 static void PrintLog(LodePNG::Decoder &decoder) {
   if(decoder.hasError()) {
     std::cout << "error " << decoder.getError() << ": " << LodePNG_error_text(decoder.getError()) << std::endl;
   } else {
     std::cout << "\n" <<
       "w: " << decoder.getWidth() << "\n" <<
       "h: " << decoder.getHeight() << "\n" <<
       "bitDepth: " << decoder.getInfoPng().color.bitDepth << "\n" <<
       "bpp: " << decoder.getBpp() << "\n" <<
       "colorChannels: " << decoder.getChannels() << "\n" <<
       "paletteSize: " << decoder.getInfoPng().color.palettesize / 4 << "\n" <<
       "colorType: " << decoder.getInfoPng().color.colorType << "\n" <<
       "compressionMethod: " << decoder.getInfoPng().compressionMethod << "\n" <<
       "filterMethod: " << decoder.getInfoPng().filterMethod << "\n" <<
       "interlaceMethod: " << decoder.getInfoPng().interlaceMethod << "\n";
     for(size_t i = 0; i < decoder.getInfoPng().text.num; i++) {
       std::cout << decoder.getInfoPng().text.keys[i] << ": " << decoder.getInfoPng().text.strings[i] << "\n";
     }
   }
 }
예제 #5
0
파일: png.cpp 프로젝트: kucerad/rpak-viz
// Load image from file [true = success, false otherwise]
bool PNG::load(string pathname){
	std::vector<unsigned char> buffer;
	LodePNG::loadFile(buffer, pathname); //load the image file with given filename
	LodePNG::Decoder decoder;
	decoder.inspect(buffer);
	if (decoder.isGreyscaleType()){
		decoder.getInfoRaw().color.colorType = 0;
		decoder.getInfoRaw().color.bitDepth = 16;
		// is grayscale

	}
	decoder.decode(image, buffer);
	width  = decoder.getWidth(); 
	height = decoder.getHeight();
	if(decoder.hasError())
	  {
		return false;
	  }
	return true;
}
예제 #6
0
  static bool Load(Image *img, ImageDesc *desc, uchar *data, int data_size) {
    //lodepng를 기반으로 적절히 로딩하기  
    SR_ASSERT(data != NULL);
    SR_ASSERT(data_size > 0);
    img->image_data_.clear();

    LodePNG::Decoder decoder;
    decoder.decode(img->image_data(), data, data_size);
    if(decoder.hasError()) { 
      return false;

    } else {
      desc->width = decoder.getWidth();
      desc->height = decoder.getHeight();
      desc->bit_depth = decoder.getInfoPng().color.bitDepth;
      desc->bpp = decoder.getBpp();
      desc->color_channels = decoder.getChannels();
      desc->is_grayscale = decoder.isGreyscaleType() > 0 ? true : false;
      desc->is_alpha = decoder.isAlphaType() > 0 ? true : false;

      return true;
    }
  }
예제 #7
0
// Entry point.
int main(int argc, char *argv[]) {                                        
      printf("------------------------------------------\n"
             "------------------------------------------\n"
             " lemmings_graphical_object by Mathew Carr \n"
             "------------------------------------------\n"
             "---------[ http://www.mrdictionary.net ]--\n"
             "------------------------------------------\n"
             "\n");
      
   // Error if you don't supply the correct number of arguments. They must all be there.
   if (argc != IDEAL_NO_MAIN_ARGUMENTS) {
      printf("Bad arguments.\n"
             "Expected lemmings_graphical_object, then the following parameters:\n"
             " - SOURCE_DIRECTORY      A path which the program can lop 00.png onto to find  \n"
             "                         your images. \n"
             " - GRAPHICAL_OBJECT_TYPE [ 0          exit | 1      entrance | 2         trap ]\n"
             "                         [ 3        hazard | 4 uninteractive | 5        water ]\n"
             " - NO_IMAGES             How many images are there in total?\n"
             " - NO_PRIMARY_IMAGES     (TRAPS) How many images in the primary animation?\n"
             " - NO_SECONDARY_IMAGES   (TRAPS) How many images in the secondary animation?\n"
             " - REPRESENTING_FRAME    What frame should be used as preview in LDS Builder?\n"
             " - TRANSPARENT_COLOUR    Which is the transparent colour in the source images?\n"
             " - HANDLE_X              Identify the active coordinate within the object.\n"
             " - HANDLE_Y              Identify the active coordinate within the object.\n"
             " - ACTIVE_ZONE_X1        Identify the active zone for exits, traps and hazards.\n"
             " - ACTIVE_ZONE_Y1        Identify the active zone for exits, traps and hazards.\n"
             " - ACTIVE_ZONE_X2        Identify the active zone for exits, traps and hazards.\n"
             " - ACTIVE_ZONE_Y2        Identify the active zone for exits, traps and hazards.\n"
             " - FLAGS                 What special flag numbers should be applied?.\n"
             " - DESCRIPTIVE_NAME      15 character description for the object. (NO SPACES)\n"
             " - OUTPUT_FILE_NAME      Specify a .LGO output file name.\n");
      return 1;
   }
   
   // If the output file exists, error.
   if (file_exists(argv[MAIN_ARGUMENT_OUTPUT_FILE_NAME])) {
      printf("Output file exists: Please delete it first.\n");
      return 1;                         
   }                     
   
   // Parse parameters:
      
   int graphical_object_type = 0;
   int no_images             = 0;
   int no_primary_images     = 0;
   int no_secondary_images   = 0;
   int representing_frame    = 0;
   int transparent_colour    = 0;
   int handle_x              = 0;
   int handle_y              = 0;
   int active_zone_x1        = 0;
   int active_zone_y1        = 0;
   int active_zone_x2        = 0;
   int active_zone_y2        = 0;
   int flags                 = 0;
   char descriptive_name[16] = {0};
   
   sscanf(argv[MAIN_ARGUMENT_GRAPHICAL_OBJECT_TYPE], "%d", &graphical_object_type);
   
   printf("Interpreted graphical object type: %d...", graphical_object_type);
   
   if ((graphical_object_type < 0)
    || (graphical_object_type > 5)) {
      printf("\nGraphical object parameter out of range.\n");         
      return 1;
   }
   
   const char *GRAPHICAL_OBJECT_TYPE_DESCRIPTION[6] = {"Exit",
                                                       "Entrance",
                                                       "Trap",
                                                       "Hazard",
                                                       "Uninteractive",
                                                       "Water",};
   
   printf(" %s\n", GRAPHICAL_OBJECT_TYPE_DESCRIPTION[graphical_object_type]);
   
   sscanf(argv[MAIN_ARGUMENT_NO_IMAGES], "%d", &no_images);
   
   printf("Interpreted no images parameter: %d.\n", no_images);
   
   if (no_images <= 0) {
      printf("Don't supply a negative number or zero for number of images!\n");      
      return 1;                                                                          
   }
   
   sscanf(argv[MAIN_ARGUMENT_NO_PRIMARY_IMAGES], "%d", &no_primary_images);
   
   printf("Interpreted no primary images parameter: %d.\n", no_primary_images);
   
   if (no_primary_images < 0) {
      printf("Don't supply a negative number for number of primary images!\n");      
      return 1;                                                                          
   }
   
   sscanf(argv[MAIN_ARGUMENT_NO_SECONDARY_IMAGES], "%d", &no_secondary_images);
   
   printf("Interpreted no secondary images parameter: %d.\n", no_secondary_images);
   
   if (no_secondary_images < 0) {
      printf("Don't supply a negative number for number of secondary images!\n");      
      return 1;                                                                          
   }
   
   sscanf(argv[MAIN_ARGUMENT_REPRESENTING_FRAME], "%d", &representing_frame);
   
   printf("Interpreted representing frame parameter: %d.\n", representing_frame);
   
   if ((representing_frame < 0) || (representing_frame >= no_images)) {
      printf("Out of range parameter for representing frame!\n");      
      return 1;                                                                          
   }
   
   sscanf(argv[MAIN_ARGUMENT_TRANSPARENT_COLOUR], "%d", &transparent_colour);
   
   printf("Interpreted transparent colour parameter: %d.\n", transparent_colour);
   
   if (transparent_colour < 0) {
      printf("Don't supply a negative number for transparent colour parameter!\n");      
      return 1;                                                                          
   }
   
   sscanf(argv[MAIN_ARGUMENT_HANDLE_X], "%d", &handle_x);
   sscanf(argv[MAIN_ARGUMENT_HANDLE_Y], "%d", &handle_y);
   
   printf("Interpreted handle parameters: %d, %d.\n", handle_x, handle_y);
   
   sscanf(argv[MAIN_ARGUMENT_ACTIVE_ZONE_X1], "%d", &active_zone_x1);
   sscanf(argv[MAIN_ARGUMENT_ACTIVE_ZONE_Y1], "%d", &active_zone_y1);
   sscanf(argv[MAIN_ARGUMENT_ACTIVE_ZONE_X2], "%d", &active_zone_x2);
   sscanf(argv[MAIN_ARGUMENT_ACTIVE_ZONE_Y2], "%d", &active_zone_y2);
   
   printf("Interpreted active zone parameters: %d, %d, %d, %d.\n", active_zone_x1, active_zone_y1,
                                                                   active_zone_x2, active_zone_y2);
   
   sscanf(argv[MAIN_ARGUMENT_FLAGS], "%d", &flags);
   
   printf("Interpreted flags parameter: %d.\n", flags);
      
   // Copy the descriptive name over.                                                              
   strncpy(descriptive_name, argv[MAIN_ARGUMENT_DESCRIPTIVE_NAME], 15);
   descriptive_name[15] = 0x00;
   
   printf("Retrieved descriptive name: '%-15s'.\n"
          "                             123456789012345\n", descriptive_name);
   
   // Set up a vector for storing graphical object frame pointers.
   // We're going to populate this as the images are loaded,
   // and then splurge them all out when the loading is
   // complete.
   std::vector<void *> graphical_object_graphic_pointers;
           // (LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *) 
   
   // We don't have a header instance yet, so we need to prepare a temporary location
   // in which to store the extracted palette.
   u16 extracted_palette[16];
   
   int read_width = 0, read_height = 0;   
                                         
   // Loop until told to quit (condition: loaded N images as specified in parameter)
   for (int frame = 0; frame < no_images; frame++) {    
      // This decoder will decode the incoming PNG images.
      LodePNG::Decoder decoder;                         
              
      // This stores the PNG file in memory while it is being worked on.
      std::vector<unsigned char> buffer;   
      
      // This stores the PNG decompressed image in memory while it is being worked on.
      std::vector<unsigned char> image;                          
      
      // This holds the filename of the file we're going to load
      char incoming_image_filename[16384];
      sprintf(incoming_image_filename, "%s%02d.png",
                                       argv[MAIN_ARGUMENT_SOURCE_DIRECTORY],
                                       frame); 
                                                                                    
      printf("%s... ", incoming_image_filename);    
      
      // Convert image filename into a std::string using this constructor.
      std::string string_incoming_image_filename = std::string(incoming_image_filename);
                     
      // Load in the terrain image PNG.
      LodePNG::loadFile(buffer, string_incoming_image_filename);  
      
      // Decode the image, retaining the image pixel index values.
      decoder.decodeGeneric(image, buffer);
      
      // Check for error here. If there's an error, we're done.
      if (decoder.hasError()) {
         if (decoder.getError() == 48) {
            printf("\nHold it! LodePNG error 48.\nDoes '%s' exist?\n", incoming_image_filename); 
         } else {
            printf("\nHold it! LodePNG error != 48.\nMalformed PNG: '%s'?\n", incoming_image_filename); 
         }
         return 1;
      }
                           
      // Get image information.
      // Get the width and height from the first image.
      if (frame == 0) {
         read_width  = decoder.getWidth();
         read_height = decoder.getHeight();   
      }
       
                                                          
      LodePNG::Decoder::Info image_info_struct = decoder.getInfo();
         
      // Get the palette size.
      unsigned long paletteSize = image_info_struct.paletteSize;
      
      printf("has %d colours.\n", paletteSize);
                                      
      // This eventuality is very, very bad.
      if ((paletteSize > 256) || (paletteSize == 0)) {                             
         printf("Detected truecolour, dying!\n");
         
         // Destroy ALL objects in the vector, and terminate.
         for (int t = 0; t < graphical_object_graphic_pointers.size(); t++) {
            printf("Killing graphic object %d.\n", t);
            delete[] ((unsigned char *)(graphical_object_graphic_pointers[t]));
         }
         
         return 1;
      }
                                   
      // Determine the amount of memory required to store a LEMMINGS_TEXTURE_ARCHIVE_TEXTURE
      // holding this image.       
      
      // This is measured in bytes.                                  
      int memory_size_required       = read_width * read_height;
      
      // Increase this to the next word.
      int memory_size_required_total = to_next(memory_size_required + sizeof(LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC), 4);
      printf("Reserved %6d bytes (%2d + %6d): %3d colour %4d by %4d texture.\n", memory_size_required_total, sizeof(LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC), memory_size_required, paletteSize, read_width, read_height);
                                                                          
      // Reserve memory for this graphic object graphic.
      LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *new_graphic_object_graphic =
           (LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *)(new unsigned char[memory_size_required_total]);   
           
      // Blank the graphic object graphic.
      memset((void *)new_graphic_object_graphic, 0, memory_size_required_total);  
                                  
      // At this pointer to the vector of pointers.                                                               
      graphical_object_graphic_pointers.push_back((void *)(new_graphic_object_graphic));                                           
                                 
      // Now all we have to do, is set the relevant fields in new_graphic_object_graphic,
      // then move onto the image.
      new_graphic_object_graphic->graphic_size = memory_size_required_total;
      
      // Rob the bytes from the buffer:
      for (int output_byte = 0; output_byte < image.size(); output_byte++) {   
         // Copy the byte from the image vector into the data array.        
            
         // The transparent colour parameter tells the program what colour
         // should be transparent.
         
         // This means that the specified colour should -become zero- when passed through the program.
         // We need to swap the transparent colour and zero.
         
         if (image[output_byte] == transparent_colour) {
            new_graphic_object_graphic->data[output_byte] = 0;
         } else
         if (image[output_byte] == 0) {
            new_graphic_object_graphic->data[output_byte] = transparent_colour;
         } else                                               
         new_graphic_object_graphic->data[output_byte] = image[output_byte];
      }
      
      // Extract the palette from the first graphic:
      if (frame == 0) {         
         for (int palette_entry = 0; palette_entry < (min(16, paletteSize)); palette_entry++) {
            int i_r, i_g, i_b; // These are the incoming palette colours.
            
            int nds_r, nds_g, nds_b; // These are the incoming colours reduced to 15-bit.
            
            i_r = image_info_struct.palette[0 + palette_entry * 4];
            i_g = image_info_struct.palette[1 + palette_entry * 4];
            i_b = image_info_struct.palette[2 + palette_entry * 4]; 
            
            // Reduce the colours to 15 bit.
            nds_r = (int)((31.9f * ((float)(i_r))) / 255.0f);
            nds_g = (int)((31.9f * ((float)(i_g))) / 255.0f);
            nds_b = (int)((31.9f * ((float)(i_b))) / 255.0f);      
                                                          
// This macro will convert 5 bit colour channel values into a composite 15 bit NDS colour with enabled alpha.
#define RGB15A(r,g,b) ((1<<15) | ((b)<<10) | ((g)<<5) | (r))

            u16 nds_colour = RGB15A(nds_r, nds_g, nds_b);
                                    
            // Fill in the palette of the level using the colours from the first graphic
            if (palette_entry == transparent_colour) {                         
               printf("This colour is transparent. Ignoring.\n");  
            } else
            if (palette_entry == 0) { 
               if (!(transparent_colour >= 16)) { 
                  printf("Extracted colour %3d: R: %2d   G: %2d   B: %2d\n", transparent_colour, nds_r, nds_g, nds_b);
               
                  extracted_palette[transparent_colour] = nds_colour;
               } else {
                  printf("Transparent colour lies >= 0x10, so we'll ignore that colour.\n");    
               }
            } else {                                      
               printf("Extracted colour %3d: R: %2d   G: %2d   B: %2d\n", palette_entry, nds_r, nds_g, nds_b);
               
               extracted_palette[palette_entry] = nds_colour;
            }
         }
      }                   
   }      
               
   printf("Forcing manic magenta on colour zero.\n");  
               
   extracted_palette[0] = 0xFC1F;
   
   // This is measured in bits, taken to the next byte, then divided again to get the number of bytes.                                  
   int memory_size_required_for_header_object_offset_array = no_images * sizeof(u32);
      
   // Increase this to the next word.
   int memory_size_required_for_header_total = to_next(memory_size_required_for_header_object_offset_array + sizeof(LEMMINGS_GRAPHICAL_OBJECT_HEADER), 4);
   printf("Reserved %4d bytes (%2d + %4d): Header must direct to %d objects.\n",
                                                                memory_size_required_for_header_total,
                                                                sizeof(LEMMINGS_GRAPHICAL_OBJECT_HEADER),
                                                                memory_size_required_for_header_object_offset_array,
                                                                no_images);
      
                                              
   // Store general information in the header.
   LEMMINGS_GRAPHICAL_OBJECT_HEADER *generated_header = (LEMMINGS_GRAPHICAL_OBJECT_HEADER *)new unsigned char[memory_size_required_for_header_total];
   
   // Blank the header.
   memset((void *)generated_header, 0, memory_size_required_for_header_total);  

   // Populate header.
   #define LEMMINGS_LEVEL_VERSION 7
   generated_header->version_number  = LEMMINGS_LEVEL_VERSION;    
   
   generated_header->graphical_object_type    = graphical_object_type;
   
   generated_header->graphic_width            = read_width;
   generated_header->graphic_height           = read_height;
   
   generated_header->no_total_frames          = no_images;
   
   generated_header->no_primary_frames        = no_primary_images;
   generated_header->no_secondary_frames      = no_secondary_images;    
   
   generated_header->representing_frame       = representing_frame;
   
   generated_header->handle_x                 = handle_x;
   generated_header->handle_y                 = handle_y;
   
   generated_header->active_zone_x1           = active_zone_x1;
   generated_header->active_zone_y1           = active_zone_y1;        
   generated_header->active_zone_x2           = active_zone_x2;
   generated_header->active_zone_y2           = active_zone_y2;
   
   generated_header->active_flags             = flags;
   
   memcpy(generated_header->graphical_object_name, descriptive_name, 16);

   // Generate offsets and file size.
   int cumulative_offset = memory_size_required_for_header_total;           
   int graphic_position  = 0;
   
   for (int t = 0; t < no_images; graphic_position++, t++) {
      // Store the current cumulative offset as the offset to this graphic.
      generated_header->graphic_offsets[graphic_position] = cumulative_offset; 
      
      printf("Graphic %3d at %6d bytes. (My length is %6d)\n", t, cumulative_offset, ((LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *)(graphical_object_graphic_pointers[t]))->graphic_size);
            
      // Advance the offset by the length of this texture chunk. 
      cumulative_offset += ((LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *)(graphical_object_graphic_pointers[t]))->graphic_size; 
   }                                         
     
   printf("\nFinal length: %6d bytes.\n", cumulative_offset);
   
   // Copy palette
   for (int palette_entry = 0; palette_entry < 16; palette_entry++) {
      generated_header->ideal_palette[palette_entry] = extracted_palette[palette_entry]; 
   }
   
   // The cumulative offset will contain the length of the final file!
   generated_header->graphical_object_file_size = cumulative_offset;
                                                                                       
   // Open output file.
   FILE *output_file = fopen(argv[MAIN_ARGUMENT_OUTPUT_FILE_NAME], "wb");
   
      // Write header, then textures.
      fwrite(generated_header, 1, memory_size_required_for_header_total, output_file);      
         
         for (int t = 0; t < no_images; t++) {
            // Write texture.
            fwrite(graphical_object_graphic_pointers[t], 1, ((LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *)(graphical_object_graphic_pointers[t]))->graphic_size, output_file);               
         }                                                      
   
   // Close output file
   fclose(output_file);    
   
   // Epilogue:                         
                                      
   // Construct a final string.
   char final_output_result_string[2048];
   
   sprintf(final_output_result_string, "Created %s (%d bytes):\n%d graphics (%d/%d).\n",
                                       argv[MAIN_ARGUMENT_OUTPUT_FILE_NAME],
                                       generated_header->graphical_object_file_size,
                                       generated_header->no_total_frames,
                                       generated_header->no_primary_frames,
                                       generated_header->no_secondary_frames);  
   
   // Destroy ALL objects in the vectors, and terminate.
   for (int t = 0; t < no_images; t++) {
      printf("Killing graphic %3d. (%d bytes)\n", t, ((LEMMINGS_GRAPHICAL_OBJECT_GRAPHIC *)(graphical_object_graphic_pointers[t]))->graphic_size);
      delete[] ((unsigned char *)(graphical_object_graphic_pointers[t]));
   }             
   
   // Destroy the header array.
   printf("Killing header.\n");
   delete[] ((unsigned char *)(generated_header));
         
   printf(final_output_result_string);            
         
   return 0;
                     
      // At this point, I would like to thank Lode Vandevenne
      // without whom this application would not have been possible.
      // Kudos to you! LodePNG has performed admirably once again!      
}