bmpread.cpp (3021B)
1 // Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 // tensorflow/lite/examples/label_image/bitmap_helpers.cc 4 5 #include "bmpread.hpp" 6 7 #include <fstream> 8 #include <stdexcept> 9 10 using namespace std::literals; 11 12 namespace { 13 14 std::vector<uint8_t> 15 bmpdecode(const uint8_t* input, 16 int row_size, 17 int width, 18 int height, 19 int channels, 20 bool top_down) 21 { 22 std::vector<uint8_t> output(height * width * channels); 23 24 for (int i = 0; i < height; i++) { 25 int src_pos; 26 int dst_pos; 27 28 for (int j = 0; j < width; j++) { 29 if (!top_down) 30 src_pos = ((height - 1 - i) * row_size) + j * channels; 31 else 32 src_pos = i * row_size + j * channels; 33 dst_pos = (i * width + j) * channels; 34 35 switch (channels) { 36 case 1: 37 output[dst_pos] = input[src_pos]; 38 break; 39 40 case 3: 41 // BGR -> RGB 42 output[dst_pos] = input[src_pos + 2]; 43 output[dst_pos + 1] = input[src_pos + 1]; 44 output[dst_pos + 2] = input[src_pos]; 45 break; 46 47 case 4: 48 // BGRA -> RGBA 49 output[dst_pos] = input[src_pos + 2]; 50 output[dst_pos + 1] = input[src_pos + 1]; 51 output[dst_pos + 2] = input[src_pos]; 52 output[dst_pos + 3] = input[src_pos + 3]; 53 break; 54 55 default: 56 throw std::runtime_error{ "Unexpected number of channels: "s + 57 std::to_string(channels) }; 58 } 59 } 60 } 61 return output; 62 } 63 64 } // namespace 65 66 std::vector<uint8_t> 67 bmpread(const std::string& input_bmp_name, 68 int* width, 69 int* height, 70 int* channels) 71 { 72 int begin, end; 73 74 std::ifstream file(input_bmp_name, std::ios::in | std::ios::binary); 75 76 if (!file) 77 throw std::runtime_error{ "input file "s + input_bmp_name + 78 " not found\n" }; 79 80 begin = file.tellg(); 81 file.seekg(0, std::ios::end); 82 end = file.tellg(); 83 size_t len = end - begin; 84 85 std::vector<uint8_t> img_bytes(len); 86 87 file.seekg(0, std::ios::beg); 88 file.read(reinterpret_cast<char*>(img_bytes.data()), len); 89 90 const int32_t header_size = 91 *(reinterpret_cast<const int32_t*>(img_bytes.data() + 10)); 92 93 *width = *(reinterpret_cast<const int32_t*>(img_bytes.data() + 18)); 94 *height = *(reinterpret_cast<const int32_t*>(img_bytes.data() + 22)); 95 96 const int32_t bpp = 97 *(reinterpret_cast<const int32_t*>(img_bytes.data() + 28)); 98 99 *channels = bpp / 8; 100 101 // there may be padding bytes when the width is not a multiple of 4 bytes 102 // 8 * channels == bits per pixel 103 const int row_size = (8 * *channels * *width + 31) / 32 * 4; 104 105 // if height is negative, data layout is top down 106 // otherwise, it's bottom up 107 bool top_down = (*height < 0); 108 109 // Decode image, allocating tensor once the image size is known 110 const uint8_t* bmp_pixels = &img_bytes[header_size]; 111 return bmpdecode( 112 bmp_pixels, row_size, *width, abs(*height), *channels, top_down); 113 }