File indexing completed on 2026-04-09 07:49:39
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <string>
0013 #include <cstring>
0014 #include <sstream>
0015 #include <iostream>
0016 #include <cassert>
0017
0018 #include "sdirectory.h"
0019 #include "np.h"
0020
0021 struct STTF ;
0022
0023
0024 struct SIMG
0025 {
0026 STTF* ttf ;
0027
0028 int width ;
0029 int height ;
0030 int channels ;
0031 unsigned char* data ;
0032 const char* loadpath ;
0033 const char* loadext ;
0034 const bool owned ;
0035
0036 SIMG(const char* path, int desired_channels=0);
0037 SIMG(int width_, int height_, int channels_, unsigned char* data_ );
0038 void setData(unsigned char* data_, bool flip_vertical=false) ;
0039 void flipVertical();
0040
0041 virtual ~SIMG();
0042
0043 std::string desc() const ;
0044
0045 void annotate( const char* bottom_line=nullptr, const char* top_line=nullptr, int line_height=24 ) ;
0046
0047 void writeNPY() const ;
0048 void writeNPY(const char* dir, const char* name) const ;
0049 void writeNPY(const char* path) const ;
0050
0051 void writePNG() const ;
0052 void writeJPG(int quality) const ;
0053
0054 void writePNG(const char* dir, const char* name) const ;
0055 void writeJPG(const char* dir, const char* name, int quality) const ;
0056
0057 void writePNG(const char* path) const ;
0058 void writeJPG(const char* path, int quality) const ;
0059
0060 static std::string FormPath(const char* dir, const char* name);
0061 static bool EndsWith( const char* s, const char* q);
0062 static const char* ChangeExt( const char* s, const char* x1, const char* x2);
0063 static const char* Ext(const char* path);
0064 };
0065
0066
0067 #ifdef __clang__
0068
0069
0070 #elif defined(__GNUC__) || defined(__GNUG__)
0071
0072 #pragma GCC diagnostic push
0073 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
0074 #pragma GCC diagnostic ignored "-Wsign-compare"
0075
0076 #elif defined(_MSC_VER)
0077
0078 #endif
0079
0080
0081 #ifdef SIMG_IMPLEMENTATION
0082
0083 #define STB_IMAGE_IMPLEMENTATION
0084 #define STB_IMAGE_WRITE_IMPLEMENTATION
0085
0086 #include "stb_image.h"
0087 #include "stb_image_write.h"
0088
0089 #endif
0090
0091 #ifdef __clang__
0092 #elif defined(__GNUC__) || defined(__GNUG__)
0093
0094 #pragma GCC diagnostic pop
0095
0096 #elif defined(_MSC_VER)
0097 #endif
0098
0099
0100
0101
0102 #define STTF_IMPLEMENTATION 1
0103 #include "STTF.h"
0104
0105
0106 inline bool SIMG::EndsWith( const char* s, const char* q)
0107 {
0108 int pos = strlen(s) - strlen(q) ;
0109 return pos > 0 && strncmp(s + pos, q, strlen(q)) == 0 ;
0110 }
0111
0112 inline const char* SIMG::ChangeExt( const char* s, const char* x1, const char* x2)
0113 {
0114 assert( EndsWith(s, x1) );
0115
0116 std::string st = s ;
0117 std::stringstream ss ;
0118
0119 ss << st.substr(0, strlen(s) - strlen(x1) ) ;
0120 ss << x2 ;
0121 std::string ns = ss.str() ;
0122 return strdup(ns.c_str());
0123 }
0124
0125
0126 inline SIMG::SIMG(const char* path, int desired_channels)
0127 :
0128 ttf(nullptr),
0129 width(0),
0130 height(0),
0131 channels(0),
0132 data(stbi_load(path, &width, &height, &channels, desired_channels)),
0133 loadpath(strdup(path)),
0134 loadext(Ext(loadpath)),
0135 owned(true)
0136 {
0137 }
0138
0139 inline SIMG::SIMG(int width_, int height_, int channels_, unsigned char* data_)
0140 :
0141 ttf(nullptr),
0142 width(width_),
0143 height(height_),
0144 channels(channels_),
0145 data(data_),
0146 loadpath("image.ppm"),
0147 loadext(Ext(loadpath)),
0148 owned(false)
0149 {
0150 }
0151
0152
0153
0154
0155 inline void SIMG::setData(unsigned char* data_, bool flip_vertical)
0156 {
0157 data = data_ ;
0158 if(flip_vertical) flipVertical();
0159 }
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 inline void SIMG::flipVertical()
0172 {
0173 for(int y=0 ; y < height/2 ; y++)
0174 for(int x=0 ; x < width ; x++)
0175 for(int c=0 ; c < channels ; c++)
0176 std::swap( data[y*width*channels + x*channels + c], data[(height-1-y)*width*channels + x*channels + c]);
0177 }
0178
0179
0180 inline SIMG::~SIMG()
0181 {
0182
0183
0184 }
0185
0186 inline std::string SIMG::desc() const
0187 {
0188 std::stringstream ss ;
0189 ss << "SIMG"
0190 << " width " << width
0191 << " height " << height
0192 << " channels " << channels
0193 << " loadpath " << ( loadpath ? loadpath : "-" )
0194 << " loadext " << ( loadext ? loadext : "-" )
0195 ;
0196 std::string s = ss.str();
0197 return s ;
0198 }
0199
0200 inline std::string SIMG::FormPath(const char* dir, const char* name)
0201 {
0202 std::stringstream ss ;
0203 ss << dir << "/" << name ;
0204 std::string s = ss.str();
0205 return s ;
0206 }
0207
0208 inline void SIMG::writeNPY() const
0209 {
0210 assert(loadpath && loadext);
0211 const char* path = ChangeExt(loadpath, loadext, ".npy" );
0212 writeNPY(path);
0213 }
0214
0215 inline void SIMG::writeNPY(const char* dir, const char* name) const
0216 {
0217 std::string pth = FormPath(dir, name);
0218 writeNPY(pth.c_str());
0219 }
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231 inline void SIMG::writeNPY(const char* path) const
0232 {
0233 std::vector<int> shape = {height, width, channels } ;
0234 np::Write( path, shape, data, "<u1" );
0235 }
0236
0237
0238 inline void SIMG::writePNG() const
0239 {
0240 assert(loadpath && loadext);
0241 const char* pngpath = ChangeExt(loadpath, loadext, ".png" );
0242 if(strcmp(pngpath, loadpath)==0)
0243 {
0244 std::cerr << "SIMG::writePNG ERROR cannot overwrite loadpath " << loadpath << "\n" ;
0245 }
0246 else
0247 {
0248 writePNG(pngpath);
0249 }
0250 }
0251
0252 inline void SIMG::writeJPG(int quality) const
0253 {
0254 assert(loadpath && loadext);
0255
0256 std::stringstream ss ;
0257 ss << "_" << quality << ".jpg" ;
0258 std::string x = ss.str();
0259
0260 const char* jpgpath = ChangeExt(loadpath, loadext, x.c_str() );
0261
0262 if(strcmp(jpgpath, loadpath)==0)
0263 {
0264 std::cerr << "SIMG::writeJPG ERROR cannot overwrite loadpath " << loadpath << "\n" ;
0265 }
0266 else
0267 {
0268 writeJPG(jpgpath, quality);
0269 }
0270 }
0271
0272
0273 inline void SIMG::writePNG(const char* dir, const char* name) const
0274 {
0275 std::string s = FormPath(dir, name);
0276 writePNG(s.c_str());
0277 }
0278
0279
0280 inline void SIMG::writeJPG(const char* dir, const char* name, int quality) const
0281 {
0282 std::string s = FormPath(dir, name);
0283 writeJPG(s.c_str(), quality);
0284 }
0285
0286
0287
0288
0289 inline void SIMG::writePNG(const char* path) const
0290 {
0291 sdirectory::MakeDirsForFile(path, 0);
0292 stbi_write_png(path, width, height, channels, data, width * channels);
0293 }
0294
0295 inline void SIMG::writeJPG(const char* path, int quality) const
0296 {
0297 assert( quality > 0 && quality <= 100 );
0298
0299
0300 sdirectory::MakeDirsForFile(path, 0);
0301
0302 stbi_write_jpg(path, width, height, channels, data, quality );
0303 }
0304
0305
0306 inline const char* SIMG::Ext(const char* path)
0307 {
0308 std::string s = path ;
0309 std::size_t pos = s.find_last_of(".");
0310 std::string ext = s.substr(pos) ;
0311 return strdup(ext.c_str());
0312 }
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 inline void SIMG::annotate( const char* bottom_line, const char* top_line, int line_height )
0327 {
0328 if(ttf == nullptr) ttf = STTF::Create() ;
0329
0330 assert(ttf);
0331 if(!ttf->valid || line_height > int(height))
0332 {
0333 std::cerr << "SIMG::annotate : ttf invalid OR line_height too large \n" ;
0334 return ;
0335 }
0336
0337 if( top_line )
0338 ttf->annotate( data, int(channels), int(width), int(height), line_height, top_line, false );
0339
0340 if( bottom_line )
0341 ttf->annotate( data, int(channels), int(width), int(height), line_height, bottom_line, true );
0342 }
0343
0344
0345