| 71 | } |
| 72 | |
| 73 | std::vector<uint8_t> read_bmp(const std::string& input_bmp_name, int* width, |
| 74 | int* height, int* channels, Settings* s) { |
| 75 | int begin, end; |
| 76 | |
| 77 | std::ifstream file(input_bmp_name, std::ios::in | std::ios::binary); |
| 78 | if (!file) { |
| 79 | LOG(FATAL) << "input file " << input_bmp_name << " not found\n"; |
| 80 | exit(-1); |
| 81 | } |
| 82 | |
| 83 | begin = file.tellg(); |
| 84 | file.seekg(0, std::ios::end); |
| 85 | end = file.tellg(); |
| 86 | size_t len = end - begin; |
| 87 | |
| 88 | if (s->verbose) LOG(INFO) << "len: " << len << "\n"; |
| 89 | |
| 90 | std::vector<uint8_t> img_bytes(len); |
| 91 | file.seekg(0, std::ios::beg); |
| 92 | file.read(reinterpret_cast<char*>(img_bytes.data()), len); |
| 93 | const int32_t header_size = |
| 94 | *(reinterpret_cast<const int32_t*>(img_bytes.data() + 10)); |
| 95 | *width = *(reinterpret_cast<const int32_t*>(img_bytes.data() + 18)); |
| 96 | *height = *(reinterpret_cast<const int32_t*>(img_bytes.data() + 22)); |
| 97 | const int32_t bpp = |
| 98 | *(reinterpret_cast<const int32_t*>(img_bytes.data() + 28)); |
| 99 | *channels = bpp / 8; |
| 100 | |
| 101 | if (s->verbose) |
| 102 | LOG(INFO) << "width, height, channels: " << *width << ", " << *height |
| 103 | << ", " << *channels << "\n"; |
| 104 | |
| 105 | // there may be padding bytes when the width is not a multiple of 4 bytes |
| 106 | // 8 * channels == bits per pixel |
| 107 | const int row_size = (8 * *channels * *width + 31) / 32 * 4; |
| 108 | |
| 109 | // if height is negative, data layout is top down |
| 110 | // otherwise, it's bottom up |
| 111 | bool top_down = (*height < 0); |
| 112 | |
| 113 | // Decode image, allocating tensor once the image size is known |
| 114 | const uint8_t* bmp_pixels = &img_bytes[header_size]; |
| 115 | return decode_bmp(bmp_pixels, row_size, *width, abs(*height), *channels, |
| 116 | top_down); |
| 117 | } |
| 118 | |
| 119 | } // namespace label_image |
| 120 | } // namespace tflite |