COR_EXPORT(Image*) CorConvertImage( Image* image, PixelFormat target_format) { COR_GUARD("CorConvertImage"); // if we don't have an image, user doesn't care about format, or // the formats match, don't do any conversion. if (!image || target_format == PF_DONTCARE || target_format == image->getFormat()) { return image; } COR_LOG("Doing the conversion..."); // if we have a palettized image, convert it to a direct color // image and then convert that if (IsPalettized(image->getFormat())) { image = ExpandPalette(image); } return DirectConversion(image, target_format); }
Image* DirectConversion(Image* image, PixelFormat target_format) { COR_GUARD("DirectConversion()"); // assert isDirect(image->getFormat()) const int width = image->getWidth(); const int height = image->getHeight(); const PixelFormat source_format = image->getFormat(); const byte* in = (byte*)image->getPixels(); if (source_format == target_format) { return image; } const int target_size = GetPixelSize(target_format); byte* out_pixels = new byte[width * height * target_size]; if (!ConvertPixels(out_pixels, target_format, in, source_format, width * height)) { delete[] out_pixels; delete image; return 0; } delete image; return new SimpleImage(width, height, target_format, out_pixels); }
COR_EXPORT(Image*) CorFlipImage( Image* image, int coordinate_axis) { COR_GUARD("CorFlipImage"); // if we don't have an image, don't flip. if (!image) { return 0; } COR_LOG("Doing the flip..."); const int width = image->getWidth(); const int height = image->getHeight(); byte* pixels = (byte*)image->getPixels(); const PixelFormat pixel_format = image->getFormat(); const int pixel_size = GetPixelSize(pixel_format); // flip about the X axis if (coordinate_axis & CA_X) { byte* row = new byte[width * pixel_size]; for (int h = 0; h < height / 2; ++h) { byte* top = pixels + h * width * pixel_size; byte* bot = pixels + (height - h - 1) * width * pixel_size; std::memcpy(row, top, width * pixel_size); std::memcpy(top, bot, width * pixel_size); std::memcpy(bot, row, width * pixel_size); } delete[] row; } // flip about the Y axis if (coordinate_axis & CA_Y) { for (int h = 0; h < height; ++h) { byte* row = pixels + h * width * pixel_size; for (int w = 0; w < width / 2; ++w) { byte* left = row + w * pixel_size; byte* right = row + (width - w - 1) * pixel_size; for (int b = 0; b < pixel_size; ++b) { std::swap(left[b], right[b]); } } } } return image; }
Image* ExpandPalette(Image* image) { COR_GUARD("ExpandPalette()"); // assert isPalettized(image->getFormat()) const int width = image->getWidth(); const int height = image->getHeight(); const byte* in = (byte*)image->getPixels(); const PixelFormat palette_format = image->getPaletteFormat(); const int pixel_size = GetPixelSize(palette_format); const byte* palette = (byte*)image->getPalette(); byte* pixels = new byte[width * height * pixel_size]; byte* out = pixels; for (int i = 0; i < width * height; ++i) { std::memcpy(out, palette + (*in) * pixel_size, pixel_size); out += pixel_size; ++in; } delete image; return new SimpleImage(width, height, palette_format, pixels); }
bool SaveJPEG(File* file, Image* image) { COR_GUARD("SaveJPEG"); if (!image) { return false; } //Hack for now FILE* filePtr = (FILE*)file->GetFilePtr(); if(!filePtr) { return false; } // If the image format isn't supported directly by this function, // clone to a supported format and try to save with that. switch (image->getFormat()) { case PF_R8G8B8: break; default: { COR_LOG("Unsupported pixel format... cloning"); std::auto_ptr<Image> cloned(CloneImage(image, PF_R8G8B8)); return SaveJPEG(file, cloned.get()); } } const int width = image->getWidth(); const int height = image->getHeight(); jpeg_compress_struct cinfo; jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); int nChannels = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); cinfo.input_components = nChannels; cinfo.num_components = nChannels; cinfo.image_width = width; cinfo.image_height = height; cinfo.data_precision = 8; cinfo.input_gamma = 1.0; jpeg_set_quality(&cinfo, 75, FALSE); jpeg_stdio_dest(&cinfo, filePtr); jpeg_start_compress(&cinfo, TRUE); unsigned char *curr_scanline = (unsigned char *)image->getPixels(); for (int y = 0; y < height; y++){ jpeg_write_scanlines(&cinfo, &curr_scanline, 1); curr_scanline += nChannels * width; } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return true; }
Image* OpenTGA(File* file) { COR_GUARD("OpenTGA"); // read header byte header[18]; if (file->read(header, 18) != 18) { return 0; } // decode header int id_length = header[0]; int cm_type = header[1]; int image_type = header[2]; //int cm_first = read16_le(header + 3); int cm_length = read16_le(header + 5); int cm_entry_size = header[7]; // in bits //int x_origin = read16_le(header + 8); //int y_origin = read16_le(header + 10); int width = read16_le(header + 12); int height = read16_le(header + 14); int pixel_depth = header[16]; int image_descriptor = header[17]; bool mirrored = (image_descriptor & (1 << 4)) != 0; // left-to-right? bool flipped = (image_descriptor & (1 << 5)) == 0; // bottom-to-top? /* * image types * 0 = no image data * 1 = uncompressed, color-mapped * 2 = uncompressed, true-color * 3 = uncompressed, black and white * 9 = RLE, color-mapped * 10 = RLE, true-color * 11 = RLE, black and white */ // make sure we support the image if (image_type != 2 || (pixel_depth != 24 && pixel_depth != 32)) { return 0; } // skip image id byte unused[255]; if (file->read(unused, id_length) != id_length) { return 0; } // skip color map if (cm_type != 0) { // allocate color map int cm_entry_bytes = (cm_entry_size + 7) / 8; int cm_size = cm_entry_bytes * cm_length; auto_array<byte> color_map(new byte[cm_size]); if (file->read(color_map, cm_size) != cm_size) { return 0; } } // read image data PixelFormat format; auto_array<byte> pixels; if (pixel_depth == 24) { COR_LOG("24-bit image"); format = PF_B8G8R8; int image_size = width * height * 3; pixels = new byte[image_size]; if (file->read(pixels, image_size) != image_size) { return 0; } } else if (pixel_depth == 32) { COR_LOG("32-bit image"); format = PF_B8G8R8A8; int image_size = width * height * 4; pixels = new byte[image_size]; if (file->read(pixels, image_size) != image_size) { return 0; } } else { return 0; } // reverse each row if (mirrored) { COR_LOG("Image is mirrored"); const int bpp = pixel_depth / 8; // bytes per pixel for (int y = 0; y < height; ++y) { // points to the first pixel of the row byte* start = pixels.get() + y * width * bpp; // points to the last pixel of the row byte* end = start + (width - 1) * bpp; while (start < end) { for (int b = 0; b < bpp; ++b) { std::swap(start[b], end[b]); } start += bpp; end -= bpp; } } } // reverse rows as a whole if (flipped) { COR_LOG("Image is flipped"); const int bpp = pixel_depth / 8; // bytes per pixel const int row_size = width * bpp; auto_array<byte> temp(new byte[row_size]); // for the swap // points to the beginning of the first row byte* start = pixels.get(); // points to the beginning of the last row byte* end = start + (height - 1) * width * bpp; while (start < end) { memcpy(temp.get(), start, row_size); memcpy(start, end, row_size); memcpy(end, temp.get(), row_size); start += row_size; end -= row_size; } } return new SimpleImage(width, height, format, pixels.release()); }
bool SavePNG(File* file, Image* image) { COR_GUARD("SavePNG"); if (!image) { return false; } // If the image format isn't supported directly by this function, // clone to a supported format and try to save with that. switch (image->getFormat()) { case PF_R8G8B8A8: case PF_R8G8B8: case PF_I8: break; default: { COR_LOG("Unsupported pixel format... cloning"); std::auto_ptr<Image> cloned(CloneImage(image, PF_R8G8B8A8)); return SavePNG(file, cloned.get()); } } // create write struct png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return false; } // error handling! if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, NULL); return false; } // create info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); return false; } int width = image->getWidth(); int height = image->getHeight(); // set image characteristics png_set_write_fn(png_ptr, file, PNG_write, PNG_flush); int color_format = 0; // png output format int color_format_bpp = 0; // png bytes per pixel bool color_format_paletted = false; // png palette needed flag // figure out output format switch (image->getFormat()) { case PF_R8G8B8A8: color_format = PNG_COLOR_TYPE_RGB_ALPHA; color_format_bpp = 4; break; case PF_R8G8B8: color_format = PNG_COLOR_TYPE_RGB; color_format_bpp = 3; break; case PF_I8: color_format = PNG_COLOR_TYPE_PALETTE; color_format_bpp = 1; color_format_paletted = true; break; default: // Unsupported format. This should already be taken care of // by the test at the beginning of this function. return false; } png_set_IHDR( png_ptr, info_ptr, width, height, 8, color_format, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (color_format_paletted) { COR_LOG("Saving palettized image..."); int image_palette_format = image->getPaletteFormat(); // palette format int image_palette_size = image->getPaletteSize(); // palette size // allocate png palette and get pointer to image palette png_color* png_palette = (png_color*)png_malloc( png_ptr, sizeof(png_color) * image_palette_size); byte* image_palette = (byte*)image->getPalette(); if (image_palette_format == PF_R8G8B8) { // 24 bit source palette for (int i = 0; i < image_palette_size; i++) { // copy entry directly png_palette[i].red = *image_palette++; png_palette[i].green = *image_palette++; png_palette[i].blue = *image_palette++; } } else if (image_palette_format == PF_R8G8B8A8) { // 32 bit source palette for (int i = 0; i < image_palette_size; i++) { // copy entry, skip alpha png_palette[i].red = *image_palette++; png_palette[i].green = *image_palette++; png_palette[i].blue = *image_palette++; image_palette++; } } // write palette png_set_PLTE(png_ptr, info_ptr, png_palette, image_palette_size); } byte* pixels = (byte*)image->getPixels(); // build rows void** rows = (void**)png_malloc(png_ptr, sizeof(void*) * height); for (int i = 0; i < height; ++i) { rows[i] = png_malloc(png_ptr, color_format_bpp * width); memcpy(rows[i], pixels, color_format_bpp * width); pixels += width * color_format_bpp; } png_set_rows(png_ptr, info_ptr, (png_bytepp)rows); info_ptr->valid |= PNG_INFO_IDAT; // actually write the image png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); return true; }