2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
18 Licensed under the Apache License, Version 2.0 (the "License");
19 you may not use this file except in compliance with the License.
20 You may obtain a copy of the License at
22 http://www.apache.org/licenses/LICENSE-2.0
24 Unless required by applicable law or agreed to in writing, software
25 distributed under the License is distributed on an "AS IS" BASIS,
26 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27 See the License for the specific language governing permissions and
28 limitations under the License.
29 ==============================================================================*/
38 #include <unistd.h> // NOLINT(build/include_order)
40 #include "bitmap_helper.h"
42 #define LOG(x) std::cerr
44 namespace StyleTransferApp
47 unsigned char *BitmapHelper::createBitmapFileHeader(int height, int width, int paddingSize)
49 int fileSize = fileHeaderSize + infoHeaderSize + (bytesPerPixel * width + paddingSize) * height;
51 static unsigned char fileHeader[] = {
53 0, 0, 0, 0, /// image file size in bytes
54 0, 0, 0, 0, /// reserved
55 0, 0, 0, 0, /// start of pixel array
58 fileHeader[0] = (unsigned char)('B');
59 fileHeader[1] = (unsigned char)('M');
60 fileHeader[2] = (unsigned char)(fileSize);
61 fileHeader[3] = (unsigned char)(fileSize >> 8);
62 fileHeader[4] = (unsigned char)(fileSize >> 16);
63 fileHeader[5] = (unsigned char)(fileSize >> 24);
64 fileHeader[10] = (unsigned char)(fileHeaderSize + infoHeaderSize);
69 unsigned char *BitmapHelper::createBitmapInfoHeader(int height, int width)
71 static unsigned char infoHeader[] = {
72 0, 0, 0, 0, /// header size
73 0, 0, 0, 0, /// image width
74 0, 0, 0, 0, /// image height
75 0, 0, /// number of color planes
76 0, 0, /// bits per pixel
77 0, 0, 0, 0, /// compression
78 0, 0, 0, 0, /// image size
79 0, 0, 0, 0, /// horizontal resolution
80 0, 0, 0, 0, /// vertical resolution
81 0, 0, 0, 0, /// colors in color table
82 0, 0, 0, 0, /// important color count
85 // Minus height means top to bottom write
88 infoHeader[0] = (unsigned char)(infoHeaderSize);
89 infoHeader[4] = (unsigned char)(width);
90 infoHeader[5] = (unsigned char)(width >> 8);
91 infoHeader[6] = (unsigned char)(width >> 16);
92 infoHeader[7] = (unsigned char)(width >> 24);
93 infoHeader[8] = (unsigned char)(height);
94 infoHeader[9] = (unsigned char)(height >> 8);
95 infoHeader[10] = (unsigned char)(height >> 16);
96 infoHeader[11] = (unsigned char)(height >> 24);
97 infoHeader[12] = (unsigned char)(1);
98 infoHeader[14] = (unsigned char)(bytesPerPixel * 8);
103 std::vector<uint8_t> BitmapHelper::decode_bmp(const uint8_t *input, int row_size, int width,
104 int height, int channels, bool top_down)
106 std::vector<uint8_t> output(height * width * channels);
107 for (int i = 0; i < height; i++)
112 for (int j = 0; j < width; j++)
116 src_pos = ((height - 1 - i) * row_size) + j * channels;
120 src_pos = i * row_size + j * channels;
123 dst_pos = (i * width + j) * channels;
128 output[dst_pos] = input[src_pos];
132 output[dst_pos] = input[src_pos + 2];
133 output[dst_pos + 1] = input[src_pos + 1];
134 output[dst_pos + 2] = input[src_pos];
138 output[dst_pos] = input[src_pos + 2];
139 output[dst_pos + 1] = input[src_pos + 1];
140 output[dst_pos + 2] = input[src_pos];
141 output[dst_pos + 3] = input[src_pos + 3];
144 LOG(FATAL) << "Unexpected number of channels: " << channels;
152 int BitmapHelper::read_bmp(const std::string &input_bmp_name, std::vector<float> &input,
153 int model_width, int model_height)
156 int width, height, channels;
158 std::ifstream file(input_bmp_name, std::ios::in | std::ios::binary);
161 LOG(FATAL) << "Error opening " << input_bmp_name << "\n";
165 begin = file.tellg();
166 file.seekg(0, std::ios::end);
168 size_t len = end - begin;
170 std::vector<uint8_t> img_bytes(len);
171 file.seekg(0, std::ios::beg);
172 file.read(reinterpret_cast<char *>(img_bytes.data()), len);
173 const int32_t header_size = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 10));
174 width = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 18));
175 height = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 22));
176 const int32_t bpp = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 28));
179 // TODO: Implement resize function
180 assert(model_width == width);
181 assert(model_height == height);
183 // there may be padding bytes when the width is not a multiple of 4 bytes
184 // 8 * channels == bits per pixel
185 const int row_size = (8 * channels * width + 31) / 32 * 4;
187 // if height is negative, data layout is top down
188 // otherwise, it's bottom up
189 bool top_down = (height < 0);
191 // Decode image, allocating tensor once the image size is known
192 const uint8_t *bmp_pixels = &img_bytes[header_size];
193 std::vector<uint8_t> bmp =
194 decode_bmp(bmp_pixels, row_size, width, abs(height), channels, top_down);
195 for (uint32_t j = 0; j < bmp.size(); j++)
197 input.push_back(static_cast<float>(bmp[j]));
202 int BitmapHelper::write_bmp(const std::string &output_bmp_name, std::vector<float> &output,
203 int width, int height, int channels)
205 std::ofstream file(output_bmp_name, std::ios::out | std::ios::binary);
208 LOG(FATAL) << "Error opening " << output_bmp_name << "\n";
212 unsigned char padding[3] = {0, 0, 0};
213 int paddingSize = (4 - (width * channels) % 4) % 4;
215 const unsigned char *fileHeader = createBitmapFileHeader(height, width, paddingSize);
216 const unsigned char *infoHeader = createBitmapInfoHeader(height, width);
218 file.write((char *)fileHeader, fileHeaderSize);
219 file.write((char *)infoHeader, infoHeaderSize);
222 for (int i = 0; i < output.size(); i += 3)
224 file << static_cast<unsigned char>(output[i + 2]);
225 file << static_cast<unsigned char>(output[i + 1]);
226 file << static_cast<unsigned char>(output[i]);
227 for (int j = 0; j < paddingSize; j++)
236 } // namespace StyleTransferApp