@@ -101,6 +101,56 @@ namespace TinyDIP
101101 }
102102 }
103103
104+ // -------------------------------------------------------------------------
105+ // write_to_csv template function implementation (OpenMP Fallback)
106+ // -------------------------------------------------------------------------
107+ template <class ElementT = double >
108+ requires TinyDIP::is_streamable<ElementT>
109+ void write_to_csv (const char * const filename, const Image<ElementT>& input, const int precision = -1 )
110+ {
111+ if (input.getDimensionality () != 2 )
112+ {
113+ throw std::runtime_error (" Input is not a 2D image!\n " );
114+ }
115+
116+ std::ofstream file (filename);
117+ if (!file.is_open ())
118+ {
119+ throw std::runtime_error (" Could not open file for writing!\n " );
120+ }
121+
122+ const std::size_t height = input.getHeight ();
123+ const std::size_t width = input.getWidth ();
124+
125+ // Pre-allocate vector size to prevent race conditions
126+ std::vector<std::string> row_strings (height);
127+
128+ #pragma omp parallel for
129+ for (std::ptrdiff_t y = 0 ; y < static_cast <std::ptrdiff_t >(height); ++y)
130+ {
131+ std::ostringstream oss;
132+ if (precision >= 0 )
133+ {
134+ oss << std::fixed << std::setprecision (precision);
135+ }
136+
137+ for (std::size_t x = 0 ; x < width; ++x)
138+ {
139+ oss << input.at_without_boundary_check (x, static_cast <std::size_t >(y));
140+ if (x < width - 1 )
141+ {
142+ oss << " ," ;
143+ }
144+ }
145+ row_strings[static_cast <std::size_t >(y)] = oss.str ();
146+ }
147+
148+ // Write appropriately sequenced rows into the target file
149+ for (std::size_t y = 0 ; y < height; ++y)
150+ {
151+ file << row_strings[y] << ' \n ' ;
152+ }
153+ }
104154 }
105155
106156 namespace pnm
0 commit comments