bool ImageManager::file_load_image(Image *img, ImageDataType type, int texture_limit, device_vector<DeviceType>& tex_img) { const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1; ImageInput *in = NULL; int width, height, depth, components; if(!file_load_image_generic(img, &in, width, height, depth, components)) { return false; } /* Read RGBA pixels. */ vector<StorageType> pixels_storage; StorageType *pixels; const size_t max_size = max(max(width, height), depth); if(max_size == 0) { /* Don't bother with invalid images. */ return false; } if(texture_limit > 0 && max_size > texture_limit) { pixels_storage.resize(((size_t)width)*height*depth*4); pixels = &pixels_storage[0]; } else { thread_scoped_lock device_lock(device_mutex); pixels = (StorageType*)tex_img.alloc(width, height, depth); } if(pixels == NULL) { /* Could be that we've run out of memory. */ return false; } bool cmyk = false; const size_t num_pixels = ((size_t)width) * height * depth; if(in) { StorageType *readpixels = pixels; vector<StorageType> tmppixels; if(components > 4) { tmppixels.resize(((size_t)width)*height*components); readpixels = &tmppixels[0]; } if(depth <= 1) { size_t scanlinesize = ((size_t)width)*components*sizeof(StorageType); in->read_image(FileFormat, (uchar*)readpixels + (height-1)*scanlinesize, AutoStride, -scanlinesize, AutoStride); } else { in->read_image(FileFormat, (uchar*)readpixels); } if(components > 4) { size_t dimensions = ((size_t)width)*height; for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { pixels[i*4+3] = tmppixels[i*components+3]; pixels[i*4+2] = tmppixels[i*components+2]; pixels[i*4+1] = tmppixels[i*components+1]; pixels[i*4+0] = tmppixels[i*components+0]; } tmppixels.clear(); } cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; in->close(); delete in; } else { if(FileFormat == TypeDesc::FLOAT) { builtin_image_float_pixels_cb(img->filename, img->builtin_data, (float*)&pixels[0], num_pixels * components, img->builtin_free_cache); } else if(FileFormat == TypeDesc::UINT8) { builtin_image_pixels_cb(img->filename, img->builtin_data, (uchar*)&pixels[0], num_pixels * components, img->builtin_free_cache); } else { /* TODO(dingto): Support half for ImBuf. */ } } /* Check if we actually have a float4 slot, in case components == 1, * but device doesn't support single channel textures. */ bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 || type == IMAGE_DATA_TYPE_BYTE4); if(is_rgba) { if(cmyk) { /* CMYK */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255; pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255; pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255; pixels[i*4+3] = alpha_one; } } else if(components == 2) { /* grayscale + alpha */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = pixels[i*2+1]; pixels[i*4+2] = pixels[i*2+0]; pixels[i*4+1] = pixels[i*2+0]; pixels[i*4+0] = pixels[i*2+0]; } } else if(components == 3) { /* RGB */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = alpha_one; pixels[i*4+2] = pixels[i*3+2]; pixels[i*4+1] = pixels[i*3+1]; pixels[i*4+0] = pixels[i*3+0]; } } else if(components == 1) { /* grayscale */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = alpha_one; pixels[i*4+2] = pixels[i]; pixels[i*4+1] = pixels[i]; pixels[i*4+0] = pixels[i]; } } if(img->use_alpha == false) { for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = alpha_one; } } } /* Make sure we don't have buggy values. */ if(FileFormat == TypeDesc::FLOAT) { /* For RGBA buffers we put all channels to 0 if either of them is not * finite. This way we avoid possible artifacts caused by fully changed * hue. */ if(is_rgba) { for(size_t i = 0; i < num_pixels; i += 4) { StorageType *pixel = &pixels[i*4]; if(!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) || !isfinite(pixel[3])) { pixel[0] = 0; pixel[1] = 0; pixel[2] = 0; pixel[3] = 0; } } } else { for(size_t i = 0; i < num_pixels; ++i) { StorageType *pixel = &pixels[i]; if(!isfinite(pixel[0])) { pixel[0] = 0; } } } } /* Scale image down if needed. */ if(pixels_storage.size() > 0) { float scale_factor = 1.0f; while(max_size * scale_factor > texture_limit) { scale_factor *= 0.5f; } VLOG(1) << "Scaling image " << img->filename << " by a factor of " << scale_factor << "."; vector<StorageType> scaled_pixels; size_t scaled_width, scaled_height, scaled_depth; util_image_resize_pixels(pixels_storage, width, height, depth, is_rgba ? 4 : 1, scale_factor, &scaled_pixels, &scaled_width, &scaled_height, &scaled_depth); StorageType *texture_pixels; { thread_scoped_lock device_lock(device_mutex); texture_pixels = (StorageType*)tex_img.alloc(scaled_width, scaled_height, scaled_depth); } memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType)); } return true; }
bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img) { ImageInput *in = NULL; int width, height, depth, components; if(!file_load_image_generic(img, &in, width, height, depth, components)) return false; /* read RGBA pixels */ uchar *pixels = (uchar*)tex_img.resize(width, height, depth); if(pixels == NULL) { return false; } bool cmyk = false; if(in) { if(depth <= 1) { int scanlinesize = width*components*sizeof(uchar); in->read_image(TypeDesc::UINT8, (uchar*)pixels + (((size_t)height)-1)*scanlinesize, AutoStride, -scanlinesize, AutoStride); } else { in->read_image(TypeDesc::UINT8, (uchar*)pixels); } cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; in->close(); delete in; } else { builtin_image_pixels_cb(img->filename, img->builtin_data, pixels); } /* Check if we actually have a byte4 slot, in case components == 1, but device * doesn't support single channel textures. */ if(type == IMAGE_DATA_TYPE_BYTE4) { size_t num_pixels = ((size_t)width) * height * depth; if(cmyk) { /* CMYK */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255; pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255; pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255; pixels[i*4+3] = 255; } } else if(components == 2) { /* grayscale + alpha */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = pixels[i*2+1]; pixels[i*4+2] = pixels[i*2+0]; pixels[i*4+1] = pixels[i*2+0]; pixels[i*4+0] = pixels[i*2+0]; } } else if(components == 3) { /* RGB */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = 255; pixels[i*4+2] = pixels[i*3+2]; pixels[i*4+1] = pixels[i*3+1]; pixels[i*4+0] = pixels[i*3+0]; } } else if(components == 1) { /* grayscale */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = 255; pixels[i*4+2] = pixels[i]; pixels[i*4+1] = pixels[i]; pixels[i*4+0] = pixels[i]; } } if(img->use_alpha == false) { for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i*4+3] = 255; } } } return true; }