bool LoadTarga( CImage32* pImage, const char* pNameFile ) { if (!(pImage && pNameFile)) { return false; } tga_image tgaImage; tga_result result = tga_read( &tgaImage, pNameFile ); if (result != TGA_NOERR) { return false; } if (tga_is_colormapped( &tgaImage )) { tga_color_unmap( &tgaImage ); } UINT width = tgaImage.width; UINT height = tgaImage.height; UINT bitsPerPixel = tgaImage.pixel_depth; pImage->Resize( width, height ); for (UINT y = 0; y < height; y ++) { for (UINT x = 0; x < width; x ++) { BYTE* pPixel = tga_find_pixel( &tgaImage, x, y ); TARGB color; if (bitsPerPixel == 8) { tga_unpack_pixel( pPixel, tgaImage.pixel_depth, &color.B, NULL, NULL, NULL ); color.G = color.R = color.B; color.A = 255; } else if (bitsPerPixel == 16 || bitsPerPixel == 24) { tga_unpack_pixel( pPixel, tgaImage.pixel_depth, &color.B, &color.G, &color.R, NULL ); color.A = 255; } else { // bitsPerPixel == 32 tga_unpack_pixel( pPixel, tgaImage.pixel_depth, &color.B, &color.G, &color.R, &color.A ); } pImage->PixelSet( x, y, color.Value ); } } tga_free_buffers( &tgaImage ); return true; }
static RGBSpectrum *ReadImageTGA(const std::string &name, int *width, int *height) { tga_image img; tga_result result; if ((result = tga_read(&img, name.c_str())) != TGA_NOERR) { Error("Unable to read from TGA file \"%s\" (%s)", name.c_str(), tga_error(result)); return nullptr; } if (tga_is_right_to_left(&img)) tga_flip_horiz(&img); if (!tga_is_top_to_bottom(&img)) tga_flip_vert(&img); if (tga_is_colormapped(&img)) tga_color_unmap(&img); *width = img.width; *height = img.height; // "Unpack" the pixels (origin in the lower left corner). // TGA pixels are in BGRA format. RGBSpectrum *ret = new RGBSpectrum[*width * *height]; RGBSpectrum *dst = ret; for (int y = *height - 1; y >= 0; y--) for (int x = 0; x < *width; x++) { uint8_t *src = tga_find_pixel(&img, x, y); if (tga_is_mono(&img)) *dst++ = RGBSpectrum(*src / 255.f); else { Float c[3]; c[2] = src[0] / 255.f; c[1] = src[1] / 255.f; c[0] = src[2] / 255.f; *dst++ = RGBSpectrum::FromRGB(c); } } tga_free_buffers(&img); Info("Read TGA image %s (%d x %d)", name.c_str(), *width, *height); return ret; }
/* --------------------------------------------------------------------------- * Convert a color-mapped image to unmapped BGR. Reallocates image_data to a * bigger size, then converts the image backwards to avoid using a secondary * buffer. Alters the necessary header fields and deallocates the color map. */ tga_result tga_color_unmap(tga_image *img) { uint8_t bpp = img->color_map_depth / 8; /* bytes per pixel */ int pos; void *tmp; if (!tga_is_colormapped(img)) return TGAERR_NOT_CMAP; if (img->pixel_depth != 8) return TGAERR_PIXEL_DEPTH; if (!SANE_DEPTH(img->color_map_depth)) return TGAERR_CMAP_DEPTH; tmp = realloc(img->image_data, img->width * img->height * bpp); if (tmp == NULL) return TGAERR_NO_MEM; img->image_data = (uint8_t*) tmp; for (pos = img->width * img->height - 1; pos >= 0; pos--) { uint8_t c_index = img->image_data[pos]; uint8_t *c_bgr = img->color_map_data + (c_index * bpp); if (c_index >= img->color_map_origin + img->color_map_length) return TGAERR_INDEX_RANGE; memcpy(img->image_data + (pos*bpp), c_bgr, (size_t)bpp); } /* clean up */ img->image_type = TGA_IMAGE_TYPE_BGR; img->pixel_depth = img->color_map_depth; free(img->color_map_data); img->color_map_data = NULL; img->color_map_type = TGA_COLOR_MAP_ABSENT; img->color_map_origin = 0; img->color_map_length = 0; img->color_map_depth = 0; return TGA_NOERR; }
/* --------------------------------------------------------------------------- * Desaturate the specified Targa using the specified coefficients: * output = ( red * cr + green * cg + blue * cb ) / dv */ tga_result tga_desaturate(tga_image *img, const int cr, const int cg, const int cb, const int dv) { uint8_t bpp = img->pixel_depth / 8; /* bytes per pixel */ uint8_t *dest, *src, *tmp; if (tga_is_mono(img)) return TGAERR_MONO; if (tga_is_colormapped(img)) { tga_result result = tga_color_unmap(img); if (result != TGA_NOERR) return result; } if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; dest = img->image_data; for (src = img->image_data; src < img->image_data + img->width*img->height*bpp; src += bpp) { uint8_t b, g, r; (void)tga_unpack_pixel(src, img->pixel_depth, &b, &g, &r, NULL); *dest = (uint8_t)( ( (int)b * cb + (int)g * cg + (int)r * cr ) / dv ); dest++; } /* shrink */ tmp = (uint8_t*)realloc(img->image_data, img->width * img->height); if (tmp == NULL) return TGAERR_NO_MEM; img->image_data = (uint8_t*)tmp; img->pixel_depth = 8; img->image_type = TGA_IMAGE_TYPE_MONO; return TGA_NOERR; }
/* --------------------------------------------------------------------------- * Writes a Targa image to <fp> from <src>. * * Returns: TGA_NOERR on success, or a TGAERR_* code on failure. * On failure, the contents of the file are not guaranteed * to be valid. */ tga_result tga_write_to_FILE(FILE *fp, const tga_image *src) { #define WRITE(srcptr, size) \ if (fwrite(srcptr, size, 1, fp) != 1) return TGAERR_WRITE #define WRITE16(src) \ { uint16_t _temp = htole16(src); \ if (fwrite(&_temp, 2, 1, fp) != 1) return TGAERR_WRITE; } WRITE(&src->image_id_length, 1); if (src->color_map_type != TGA_COLOR_MAP_ABSENT && src->color_map_type != TGA_COLOR_MAP_PRESENT) return TGAERR_CMAP_TYPE; WRITE(&src->color_map_type, 1); if (src->image_type == TGA_IMAGE_TYPE_NONE) return TGAERR_NO_IMG; if (src->image_type != TGA_IMAGE_TYPE_COLORMAP && src->image_type != TGA_IMAGE_TYPE_BGR && src->image_type != TGA_IMAGE_TYPE_MONO && src->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE && src->image_type != TGA_IMAGE_TYPE_BGR_RLE && src->image_type != TGA_IMAGE_TYPE_MONO_RLE) return TGAERR_IMG_TYPE; WRITE(&src->image_type, 1); if (tga_is_colormapped(src) && src->color_map_type == TGA_COLOR_MAP_ABSENT) return TGAERR_CMAP_MISSING; if (!tga_is_colormapped(src) && src->color_map_type == TGA_COLOR_MAP_PRESENT) return TGAERR_CMAP_PRESENT; if (src->color_map_type == TGA_COLOR_MAP_PRESENT) { if (src->color_map_length == 0) return TGAERR_CMAP_LENGTH; if (!UNMAP_DEPTH(src->color_map_depth)) return TGAERR_CMAP_DEPTH; } WRITE16(src->color_map_origin); WRITE16(src->color_map_length); WRITE(&src->color_map_depth, 1); WRITE16(src->origin_x); WRITE16(src->origin_y); if (src->width == 0 || src->height == 0) return TGAERR_ZERO_SIZE; WRITE16(src->width); WRITE16(src->height); if (!SANE_DEPTH(src->pixel_depth) || (src->pixel_depth != 8 && tga_is_colormapped(src)) ) return TGAERR_PIXEL_DEPTH; WRITE(&src->pixel_depth, 1); WRITE(&src->image_descriptor, 1); if (src->image_id_length > 0) WRITE(&src->image_id, src->image_id_length); if (src->color_map_type == TGA_COLOR_MAP_PRESENT) WRITE(src->color_map_data + (src->color_map_origin * src->color_map_depth / 8), src->color_map_length * src->color_map_depth / 8); if (tga_is_rle(src)) { uint16_t row; for (row=0; row<src->height; row++) { tga_result result = tga_write_row_RLE(fp, src, src->image_data + row*src->width*src->pixel_depth/8); if (result != TGA_NOERR) return result; } } else { /* uncompressed */ WRITE(src->image_data, src->width * src->height * src->pixel_depth / 8); } WRITE(tga_id, tga_id_length); return TGA_NOERR; #undef WRITE #undef WRITE16 }
/* --------------------------------------------------------------------------- * Read a Targa image from <fp> to <dest>. * * Returns: TGA_NOERR on success, or a TGAERR_* code on failure. In the * case of failure, the contents of dest are not guaranteed to be * valid. */ tga_result tga_read_from_FILE(tga_image *dest, FILE *fp) { #define BARF(errcode) \ { tga_free_buffers(dest); return errcode; } #define READ(destptr, size) \ if (fread(destptr, size, 1, fp) != 1) BARF(TGAERR_EOF) #define READ16(dest) \ { if (fread(&(dest), 2, 1, fp) != 1) BARF(TGAERR_EOF); \ dest = letoh16(dest); } dest->image_id = NULL; dest->color_map_data = NULL; dest->image_data = NULL; READ(&dest->image_id_length,1); READ(&dest->color_map_type,1); if (dest->color_map_type != TGA_COLOR_MAP_ABSENT && dest->color_map_type != TGA_COLOR_MAP_PRESENT) BARF(TGAERR_CMAP_TYPE); READ(&dest->image_type, 1); if (dest->image_type == TGA_IMAGE_TYPE_NONE) BARF(TGAERR_NO_IMG); if (dest->image_type != TGA_IMAGE_TYPE_COLORMAP && dest->image_type != TGA_IMAGE_TYPE_BGR && dest->image_type != TGA_IMAGE_TYPE_MONO && dest->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE && dest->image_type != TGA_IMAGE_TYPE_BGR_RLE && dest->image_type != TGA_IMAGE_TYPE_MONO_RLE) BARF(TGAERR_IMG_TYPE); if (tga_is_colormapped(dest) && dest->color_map_type == TGA_COLOR_MAP_ABSENT) BARF(TGAERR_CMAP_MISSING); if (!tga_is_colormapped(dest) && dest->color_map_type == TGA_COLOR_MAP_PRESENT) BARF(TGAERR_CMAP_PRESENT); READ16(dest->color_map_origin); READ16(dest->color_map_length); READ(&dest->color_map_depth, 1); if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) { if (dest->color_map_length == 0) BARF(TGAERR_CMAP_LENGTH); if (!UNMAP_DEPTH(dest->color_map_depth)) BARF(TGAERR_CMAP_DEPTH); } READ16(dest->origin_x); READ16(dest->origin_y); READ16(dest->width); READ16(dest->height); if (dest->width == 0 || dest->height == 0) BARF(TGAERR_ZERO_SIZE); READ(&dest->pixel_depth, 1); if (!SANE_DEPTH(dest->pixel_depth) || (dest->pixel_depth != 8 && tga_is_colormapped(dest)) ) BARF(TGAERR_PIXEL_DEPTH); READ(&dest->image_descriptor, 1); if (dest->image_id_length > 0) { dest->image_id = (uint8_t*)malloc(dest->image_id_length); if (dest->image_id == NULL) BARF(TGAERR_NO_MEM); READ(dest->image_id, dest->image_id_length); } if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) { dest->color_map_data = (uint8_t*)malloc( (dest->color_map_origin + dest->color_map_length) * dest->color_map_depth / 8); if (dest->color_map_data == NULL) BARF(TGAERR_NO_MEM); READ(dest->color_map_data + (dest->color_map_origin * dest->color_map_depth / 8), dest->color_map_length * dest->color_map_depth / 8); } dest->image_data = (uint8_t*) malloc( dest->width * dest->height * dest->pixel_depth / 8); if (dest->image_data == NULL) BARF(TGAERR_NO_MEM); if (tga_is_rle(dest)) { /* read RLE */ tga_result result = tga_read_rle(dest, fp); if (result != TGA_NOERR) BARF(result); } else { /* uncompressed */ READ(dest->image_data, dest->width * dest->height * dest->pixel_depth / 8); } return TGA_NOERR; #undef BARF #undef READ #undef READ16 }
/* --------------------------------------------------------------------------- * Convert an image to the given pixel depth. (one of 32, 24, 16) Avoids * using a secondary buffer to do the conversion. */ tga_result tga_convert_depth(tga_image *img, const uint8_t bits) { size_t src_size, dest_size; uint8_t src_bpp, dest_bpp; uint8_t *src, *dest; if (!UNMAP_DEPTH(bits) || !SANE_DEPTH(img->pixel_depth) ) return TGAERR_PIXEL_DEPTH; if (tga_is_colormapped(img)) { tga_result result = tga_color_unmap(img); if (result != TGA_NOERR) return result; } if (img->pixel_depth == bits) return TGA_NOERR; /* no op, no err */ src_bpp = img->pixel_depth / 8; dest_bpp = bits / 8; src_size = (size_t)( img->width * img->height * src_bpp ); dest_size = (size_t)( img->width * img->height * dest_bpp ); if (src_size > dest_size) { void *tmp; /* convert forwards */ dest = img->image_data; for (src = img->image_data; src < img->image_data + img->width * img->height * src_bpp; src += src_bpp) { uint8_t r,g,b,a; (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a); (void)tga_pack_pixel(dest, bits, r, g, b, a); dest += dest_bpp; } /* shrink */ tmp = realloc(img->image_data, img->width * img->height * dest_bpp); if (tmp == NULL) return TGAERR_NO_MEM; img->image_data = (uint8_t*)tmp; } else { /* expand */ void *tmp = realloc(img->image_data, img->width * img->height * dest_bpp); if (tmp == NULL) return TGAERR_NO_MEM; img->image_data = (uint8_t*) tmp; /* convert backwards */ dest = img->image_data + (img->width*img->height - 1) * dest_bpp; for (src = img->image_data + (img->width*img->height - 1) * src_bpp; src >= img->image_data; src -= src_bpp) { uint8_t r,g,b,a; (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a); (void)tga_pack_pixel(dest, bits, r, g, b, a); dest -= dest_bpp; } } img->pixel_depth = bits; return TGA_NOERR; }
bool loadDepth(const char* pNameFile, ImageBase** ppImage) { if (!pNameFile || !ppImage || *ppImage) return false; tga_image tgaImage; tga_result result = tga_read(&tgaImage, pNameFile); if (result != TGA_NOERR) return false; if (tga_is_colormapped(&tgaImage)) { tga_color_unmap(&tgaImage); } unsigned int width = tgaImage.width; unsigned int height = tgaImage.height; unsigned int bitsPerPixel = tgaImage.pixel_depth; if (bitsPerPixel != 32) return false; // depth の最大値・最小値を取得 unsigned long minValueDepth = ULONG_MAX; unsigned long maxValueDepth = 0; for (unsigned int y = 0; y < tgaImage.height; y ++) { for (unsigned int x = 0; x < tgaImage.width; x ++) { unsigned char* pPixel = tga_find_pixel(&tgaImage, x, y); unsigned char valueR = 0, valueG = 0, valueB = 0, valueA = 0; tga_unpack_pixel(pPixel, tgaImage.pixel_depth, &valueB, &valueG, &valueR, &valueA); unsigned long valueDepth = ((unsigned int)(valueA) << 24) | ((unsigned int)(valueR) << 16) | ((unsigned int)(valueG) << 8) | (unsigned int)(valueB); if (valueDepth < minValueDepth) minValueDepth = valueDepth; if (maxValueDepth < valueDepth) maxValueDepth = valueDepth; } } // 最大値・最小値をもとに正規化 unsigned char maxValueElement = ElementUtil::getMaxValue<ImageGray8::TypeElement>(); unsigned char minValueElement = ElementUtil::getMinValue<ImageGray8::TypeElement>(); ImageGray8 *pImage = ImageFactory::createImage<ImageGray8>(tgaImage.width, tgaImage.height); for (unsigned int y = 0; y < tgaImage.height; y ++) { for (unsigned int x = 0; x < tgaImage.width; x ++) { unsigned char* pPixel = tga_find_pixel(&tgaImage, x, y); unsigned char valueR = 0, valueG = 0, valueB = 0, valueA = 0; tga_unpack_pixel(pPixel, tgaImage.pixel_depth, &valueB, &valueG, &valueR, &valueA); unsigned long valueDepth = ((unsigned int)(valueA) << 24) | ((unsigned int)(valueR) << 16) | ((unsigned int)(valueG) << 8) | (unsigned int)(valueB); unsigned char valueNormalized = cropValue<unsigned char>((unsigned char)(float(maxValueElement) * float(valueDepth - minValueDepth) / float(maxValueDepth - minValueDepth)), minValueElement, maxValueElement); unsigned char value = maxValueElement - valueNormalized; pImage->setPixel(x, y, ImageGray8::TypePixel(value)); } } tga_free_buffers(&tgaImage); *ppImage = static_cast<ImageBase*>(pImage); return pImage ? true : false; }