6211ea4763f2d7e5ab2e4ee53b91a36eb061b4b9
[platform/core/ml/nnfw.git] / runtime / contrib / style_transfer_app / src / bitmap_helper.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
17
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
21
22     http://www.apache.org/licenses/LICENSE-2.0
23
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 ==============================================================================*/
30
31 #include <cassert>
32 #include <cstdint>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <fstream>
36 #include <iostream>
37
38 #include <unistd.h> // NOLINT(build/include_order)
39
40 #include "bitmap_helper.h"
41
42 #define LOG(x) std::cerr
43
44 namespace StyleTransferApp
45 {
46
47 unsigned char *BitmapHelper::createBitmapFileHeader(int height, int width, int paddingSize)
48 {
49   int fileSize = fileHeaderSize + infoHeaderSize + (bytesPerPixel * width + paddingSize) * height;
50
51   static unsigned char fileHeader[] = {
52       0, 0,       /// signature
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
56   };
57
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);
65
66   return fileHeader;
67 }
68
69 unsigned char *BitmapHelper::createBitmapInfoHeader(int height, int width)
70 {
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
83   };
84
85   // Minus height means top to bottom write
86   height = -height;
87
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);
99
100   return infoHeader;
101 }
102
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)
105 {
106   std::vector<uint8_t> output(height * width * channels);
107   for (int i = 0; i < height; i++)
108   {
109     int src_pos;
110     int dst_pos;
111
112     for (int j = 0; j < width; j++)
113     {
114       if (!top_down)
115       {
116         src_pos = ((height - 1 - i) * row_size) + j * channels;
117       }
118       else
119       {
120         src_pos = i * row_size + j * channels;
121       }
122
123       dst_pos = (i * width + j) * channels;
124
125       switch (channels)
126       {
127         case 1:
128           output[dst_pos] = input[src_pos];
129           break;
130         case 3:
131           // BGR -> RGB
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];
135           break;
136         case 4:
137           // BGRA -> RGBA
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];
142           break;
143         default:
144           LOG(FATAL) << "Unexpected number of channels: " << channels;
145           break;
146       }
147     }
148   }
149   return output;
150 }
151
152 int BitmapHelper::read_bmp(const std::string &input_bmp_name, std::vector<float> &input,
153                            int model_width, int model_height)
154 {
155   int begin, end;
156   int width, height, channels;
157
158   std::ifstream file(input_bmp_name, std::ios::in | std::ios::binary);
159   if (!file)
160   {
161     LOG(FATAL) << "Error opening " << input_bmp_name << "\n";
162     exit(-1);
163   }
164
165   begin = file.tellg();
166   file.seekg(0, std::ios::end);
167   end = file.tellg();
168   size_t len = end - begin;
169
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));
177   channels = bpp / 8;
178
179   // TODO: Implement resize function
180   assert(model_width == width);
181   assert(model_height == height);
182
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;
186
187   // if height is negative, data layout is top down
188   // otherwise, it's bottom up
189   bool top_down = (height < 0);
190
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++)
196   {
197     input.push_back(static_cast<float>(bmp[j]));
198   }
199   return 0;
200 }
201
202 int BitmapHelper::write_bmp(const std::string &output_bmp_name, std::vector<float> &output,
203                             int width, int height, int channels)
204 {
205   std::ofstream file(output_bmp_name, std::ios::out | std::ios::binary);
206   if (!file)
207   {
208     LOG(FATAL) << "Error opening " << output_bmp_name << "\n";
209     exit(-1);
210   }
211
212   unsigned char padding[3] = {0, 0, 0};
213   int paddingSize = (4 - (width * channels) % 4) % 4;
214
215   const unsigned char *fileHeader = createBitmapFileHeader(height, width, paddingSize);
216   const unsigned char *infoHeader = createBitmapInfoHeader(height, width);
217
218   file.write((char *)fileHeader, fileHeaderSize);
219   file.write((char *)infoHeader, infoHeaderSize);
220
221   // RGB to BGR
222   for (int i = 0; i < output.size(); i += 3)
223   {
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++)
228     {
229       file << padding;
230     }
231   }
232   file.close();
233   return 0;
234 }
235
236 } // namespace StyleTransferApp