Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpImageIoStb.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * stb backend for JPEG and PNG image I/O operations.
32 */
33
38
39#include <visp3/core/vpConfig.h>
40
41#if defined(VISP_HAVE_STBIMAGE)
42
43#include "vpImageIoBackend.h"
44#include <visp3/core/vpImageConvert.h>
45
46#if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2)
47#define VISP_HAVE_SSE2 1
48#endif
49
50#ifndef VISP_HAVE_SSE2
51#define STBI_NO_SIMD
52#endif
53
54#define STB_IMAGE_IMPLEMENTATION
55#include <stb_image.h>
56
57#define STB_IMAGE_WRITE_IMPLEMENTATION
58#include <stb_image_write.h>
59
61
62void readStb(vpImage<unsigned char> &I, const std::string &filename)
63{
64 int width = 0, height = 0, channels = 0;
65 unsigned char *image = stbi_load(filename.c_str(), &width, &height, &channels, STBI_grey);
66 if (image == nullptr) {
67 throw(vpImageException(vpImageException::ioError, "Can't read the image: %s", filename.c_str()));
68 }
69 I.init(image, static_cast<unsigned int>(height), static_cast<unsigned int>(width), true);
70 stbi_image_free(image);
71}
72
73void readStb(vpImage<vpRGBa> &I, const std::string &filename)
74{
75 int width = 0, height = 0, channels = 0;
76 unsigned char *image = stbi_load(filename.c_str(), &width, &height, &channels, STBI_rgb_alpha);
77 if (image == nullptr) {
78 throw(vpImageException(vpImageException::ioError, "Can't read the image: %s", filename.c_str()));
79 }
80 I.init(reinterpret_cast<vpRGBa *>(image), static_cast<unsigned int>(height), static_cast<unsigned int>(width), true);
81 stbi_image_free(image);
82}
83
84void writeJPEGStb(const vpImage<unsigned char> &I, const std::string &filename, int quality)
85{
86 int res = stbi_write_jpg(filename.c_str(), static_cast<int>(I.getWidth()), static_cast<int>(I.getHeight()), STBI_grey,
87 reinterpret_cast<void *>(I.bitmap), quality);
88 if (res == 0) {
89 throw(vpImageException(vpImageException::ioError, "JEPG write error"));
90 }
91}
92
93void writeJPEGStb(const vpImage<vpRGBa> &I, const std::string &filename, int quality)
94{
95 int res = stbi_write_jpg(filename.c_str(), static_cast<int>(I.getWidth()), static_cast<int>(I.getHeight()),
96 STBI_rgb_alpha, reinterpret_cast<void *>(I.bitmap), quality);
97 if (res == 0) {
98 throw(vpImageException(vpImageException::ioError, "JEPG write error"));
99 }
100}
101
102void writePNGStb(const vpImage<unsigned char> &I, const std::string &filename)
103{
104 const int stride_in_bytes = static_cast<int>(I.getWidth());
105 int res = stbi_write_png(filename.c_str(), static_cast<int>(I.getWidth()), static_cast<int>(I.getHeight()), STBI_grey,
106 reinterpret_cast<void *>(I.bitmap), stride_in_bytes);
107 if (res == 0) {
108 throw(vpImageException(vpImageException::ioError, "PNG write error: %s", filename.c_str()));
109 }
110}
111
112void writePNGStb(const vpImage<vpRGBa> &I, const std::string &filename)
113{
114 const int stride_in_bytes = static_cast<int>(4 * I.getWidth());
115 int res = stbi_write_png(filename.c_str(), static_cast<int>(I.getWidth()), static_cast<int>(I.getHeight()),
116 STBI_rgb_alpha, reinterpret_cast<void *>(I.bitmap), stride_in_bytes);
117 if (res == 0) {
118 throw(vpImageException(vpImageException::ioError, "PNG write error: %s", filename.c_str()));
119 }
120}
121
122namespace
123{
124typedef struct
125{
126 int last_pos;
127 void *context;
128} custom_stbi_mem_context;
129
130// custom write function
131static void custom_stbi_write_mem(void *context, void *data, int size)
132{
133 custom_stbi_mem_context *c = (custom_stbi_mem_context *)context;
134 char *dst = (char *)c->context;
135 char *src = (char *)data;
136 int cur_pos = c->last_pos;
137 for (int i = 0; i < size; ++i) {
138 dst[cur_pos++] = src[i];
139 }
140 c->last_pos = cur_pos;
141}
142}
143
150void readPNGfromMemStb(const std::vector<unsigned char> &buffer, vpImage<unsigned char> &I)
151{
152 int x = 0, y = 0, comp = 0;
153 const int req_channels = 1;
154 unsigned char *buffer_read = stbi_load_from_memory(buffer.data(), static_cast<int>(buffer.size()), &x, &y, &comp, req_channels);
155 assert(comp == req_channels);
156
157 I.init(buffer_read, y, x, true);
158 STBI_FREE(buffer_read);
159}
160
167void readPNGfromMemStb(const std::vector<unsigned char> &buffer, vpImage<vpRGBa> &I_color)
168{
169 int x = 0, y = 0, comp = 0;
170 unsigned char *buffer_read = stbi_load_from_memory(buffer.data(), static_cast<int>(buffer.size()), &x, &y, &comp, 0);
171
172 if (comp == 4) {
173 const bool copyData = true;
174 I_color.init(reinterpret_cast<vpRGBa *>(buffer_read), y, x, copyData);
175 }
176 else if (comp == 3) {
177 I_color.init(y, x);
178 const bool flip = false;
179 vpImageConvert::RGBToRGBa(buffer_read, reinterpret_cast<unsigned char *>(I_color.bitmap), x, y, flip);
180 }
181 else {
182 STBI_FREE(buffer_read);
183
184#if VISP_CXX_STANDARD > VISP_CXX_STANDARD_98
185 std::string message = "Wrong number of channels for the input buffer: " + std::to_string(comp);
187#else
188 throw(vpImageException(vpImageException::ioError, "Wrong number of channels for the input buffer: %d", comp));
189#endif
190 }
191
192 STBI_FREE(buffer_read);
193}
194
201void writePNGtoMemStb(const vpImage<unsigned char> &I, std::vector<unsigned char> &buffer)
202{
203 const int height = I.getRows();
204 const int width = I.getCols();
205 const int channels = 1;
206
207 custom_stbi_mem_context context;
208 context.last_pos = 0;
209 buffer.resize(I.getHeight() * I.getWidth());
210 context.context = (void *)buffer.data();
211
212 const int stride_bytes = 0;
213 int result = stbi_write_png_to_func(custom_stbi_write_mem, &context, width, height, channels, I.bitmap, stride_bytes);
214
215 if (result) {
216 buffer.resize(context.last_pos);
217 }
218 else {
219#if VISP_CXX_STANDARD > VISP_CXX_STANDARD_98
220 std::string message = "Cannot write png to memory, result: " + std::to_string(result);
222#else
223 throw(vpImageException(vpImageException::ioError, "Cannot write png to memory, result: %d", result));
224#endif
225 }
226}
227
235void writePNGtoMemStb(const vpImage<vpRGBa> &I_color, std::vector<unsigned char> &buffer, bool saveAlpha)
236{
237 const int height = I_color.getRows();
238 const int width = I_color.getCols();
239 const int channels = saveAlpha ? 4 : 3;
240
241 custom_stbi_mem_context context;
242 context.last_pos = 0;
243 buffer.resize(height * width * channels);
244 context.context = (void *)buffer.data();
245
246 const int stride_bytes = 0;
247 int result = 0;
248 if (saveAlpha) {
249 result = stbi_write_png_to_func(custom_stbi_write_mem, &context, width, height, channels,
250 reinterpret_cast<unsigned char *>(I_color.bitmap), stride_bytes);
251 }
252 else {
253 unsigned char *bitmap = new unsigned char[height * width * channels];
254 vpImageConvert::RGBaToRGB(reinterpret_cast<unsigned char *>(I_color.bitmap), bitmap, height*width);
255 result = stbi_write_png_to_func(custom_stbi_write_mem, &context, width, height, channels, bitmap, stride_bytes);
256 delete[] bitmap;
257 }
258
259 if (result) {
260 buffer.resize(context.last_pos);
261 }
262 else {
263#if VISP_CXX_STANDARD > VISP_CXX_STANDARD_98
264 std::string message = "Cannot write png to memory, result: " + std::to_string(result);
266#else
267 throw(vpImageException(vpImageException::ioError, "Cannot write png to memory, result: %d", result));
268#endif
269 }
270}
271
272END_VISP_NAMESPACE
273
274#endif
static void RGBToRGBa(unsigned char *rgb, unsigned char *rgba, unsigned int size)
static void RGBaToRGB(unsigned char *rgba, unsigned char *rgb, unsigned int size)
Error that can be emitted by the vpImage class and its derivatives.
@ ioError
Image io error.
Definition of the vpImage class member functions.
Definition vpImage.h:131
void init(unsigned int height, unsigned int width)
Set the size of the image.
Definition vpImage.h:387
unsigned int getCols() const
Definition vpImage.h:171
Type * bitmap
points toward the bitmap
Definition vpImage.h:135
unsigned int getRows() const
Definition vpImage.h:212