Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:39

0001 #pragma once
0002 /**
0003 SIMG.h : High Level Image load/save methods implemented with stb_image.h 
0004 ===========================================================================
0005 
0006 Note that STTF managed truetype fonts are now handled with an 
0007 internal instance rather than a global one from SLOG as this
0008 simplifies dependencies enabling headeronly access to this functionality. 
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);   // 0:asis channels 
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) // static 
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)  // static
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 SIMG::flipVertical
0164 -------------------
0165 
0166 Used via SIMG::setData from CSGOptiX/Frame.cc Frame::download
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     // getting linker error with the below when using in CMake project, but not in standalone testing 
0183     //if(owned) stbi_image_free((void*)data);    
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 SIMG::writeNPY
0223 --------------
0224 
0225 View the array as an image in matplotlib with plt.imshow as demonstrated
0226 in sysrap/tests/SIMGTest.py and "ana" command of sysrap/tests/SIMGTest.sh 
0227 (similar to the old npy/ImageNPY.hpp)
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     //std::cout << "SIMG::writeJPG [" << ( path ? path : "-" ) << "]" << std::endl ; 
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 SIMG::annotate
0318 ---------------
0319 
0320 Accessing ttf in the ctor rather than doing it here at point of use turns out to be flakey somehow ?
0321 Possibly related to this being implemented in the header ?
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