Cogs.Core
ImageDecoder.cpp
1#define STB_IMAGE_IMPLEMENTATION
2#include "stb_image.h"
3
4#include "ImageDecoder.h"
5#include "GeoTiff.h"
6
7namespace {
8 using namespace Cogs::Core::TerrainProvider;
9}
10
11Cogs::Core::TerrainProvider::ImageDecoder::~ImageDecoder()
12{
13 if (stb_data) {
14 stbi_image_free(stb_data);
15 }
16
17}
18
19bool Cogs::Core::TerrainProvider::ImageDecoder::decode(Cogs::TileData& tileData,
20 Memory::MemoryBuffer& input, MimeType kind,
21 unsigned suggested_width,
22 unsigned suggested_height,
23 float suggested_nodata)
24{
25 switch (kind) {
26 case MimeType::Png:
27 case MimeType::Gif:
28 case MimeType::Jpeg: {
29 int width, height, comp;
30 stbi_set_flip_vertically_on_load_thread(1);
31 stb_data = stbi_load_from_memory((const stbi_uc*)input.data(),
32 static_cast<int>(input.size()),
33 &width,
34 &height,
35 &comp, 4);
36 tileData.format = Cogs::TextureFormat::R8G8B8A8_UNORM_SRGB;
37 tileData.width = width;
38 tileData.height = height;
39 tileData.stride = 0;
40 tileData.imageData = stb_data;
41 tileData.flags = Cogs::TileDataFlags::None;
42 break;
43 }
44 case MimeType::Tiff: {
45 GeoTiffView geotiff(input.data(), input.size());
46 if (!geotiff.getFullImage(output, suggested_nodata)) {
47 tileData.imageData = nullptr;
48 return false;
49 }
50 tileData.format = geotiff.format;
51 tileData.width = geotiff.width;
52 tileData.height = geotiff.height;
53 tileData.stride = 0;
54 tileData.imageData = output.data();
55 tileData.minZ = geotiff.minSample.value_or(0.f);
56 tileData.maxZ = geotiff.maxSample.value_or(0.f);
58 break;
59 }
60
61 case MimeType::F32: {
62 if (input.size() != sizeof(float) * suggested_width * suggested_height) {
63 tileData.imageData = nullptr;
64 return false;
65 }
66
67 float min = std::numeric_limits<float>::max();
68 float max = -std::numeric_limits<float>::max();
69 float* image = (float*)input.data();
70 for (size_t i = 0, n = input.size() / sizeof(float); i < n; i++) {
71 min = std::min(min, image[i]);
72 max = std::max(max, image[i]);
73 }
74
75 tileData.format = Cogs::TextureFormat::R32_FLOAT;
76 tileData.width = suggested_width;
77 tileData.height = suggested_height;
78 tileData.stride = 0;
79 tileData.imageData = input.data();
80 tileData.minZ = min;
81 tileData.maxZ = max;
82 tileData.flags = Cogs::TileDataFlags::None | Cogs::TileDataFlags::IsHeight;
83 break;
84 }
85 case MimeType::RGBA8:
86 if (input.size() != 4 * sizeof(uint8_t) * suggested_width * suggested_height) {
87 tileData.imageData = nullptr;
88 return false;
89 }
90
91 tileData.format = Cogs::TextureFormat::R8G8B8A8_UNORM_SRGB;
92 tileData.width = suggested_width;
93 tileData.height = suggested_height;
94 tileData.stride = 0;
95 tileData.imageData = input.data();
96 tileData.flags = Cogs::TileDataFlags::None;
97 break;
98
99 case MimeType::XML:
100 default:
101 tileData.imageData = nullptr;
102 return false;
103 }
104 return true;
105}
@ ShouldFlip
Tile data should be flipped on the Y axis.
@ LinearColorSpace
Target format of conversion should be in linear (non-sRGB) color space.
@ IsHeight
Tile contains height data, min/max values should be provided.