static std::pair<bool, String> save_png_gdiplus(const Path &filename, const ImageRGB &img) { // gdi+ does not support URIs Path winname(filename); winname.ToWindows(); const auto newsize = winname.Size() + 1; auto wcstring = std::vector<wchar_t>(newsize); auto convertedChars = size_t(0); mbstowcs_s(&convertedChars, wcstring.data(), newsize, winname.CStr(), _TRUNCATE); Gdiplus::Bitmap *outbm = new Gdiplus::Bitmap(INT(img.GetWidth()), INT(img.GetHeight()), PixelFormat24bppRGB); if (!outbm) { return std::make_pair(false, String(_("Cannot create bitmap"))); } Gdiplus::BitmapData bitmapData; auto clip = Gdiplus::Rect(0, 0, outbm->GetWidth(), outbm->GetHeight()); outbm->LockBits(&clip, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); auto *pixels = (uint8_t*)bitmapData.Scan0; //#pragma omp parallel for FOREACHPIXEL(x, y, img) { size_t poffset = 3 * x + y * bitmapData.Stride; const auto &pix = img.At(x, y); pixels[poffset + 2] = pix.r; pixels[poffset + 1] = pix.g; pixels[poffset] = pix.b; }
static std::pair<bool, String> save_png_gdkpixbuf(const Path &fname, const ImageRGB &img) { GdkPixbuf *pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, int(img.GetWidth()), int(img.GetHeight())); if (!pb) { return std::make_pair(false, String(_("Cannot create temporary buffer."))); } int w = gdk_pixbuf_get_width(pb); int h = gdk_pixbuf_get_height(pb); int rs = gdk_pixbuf_get_rowstride(pb); guchar *ppix = gdk_pixbuf_get_pixels(pb); for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { const auto px = img.At(x, y); int o2 = x + x + x + y * rs; ppix[o2] = px.r; ppix[o2 + 1] = px.g; ppix[o2 + 2] = px.b; } GError *err = NULL; gchar *utfname; gsize i; utfname = g_locale_to_utf8(fname.CStr(), -1, NULL, &i, NULL); gchar *filename; filename = g_filename_from_utf8(utfname, -1, NULL, &i, NULL); g_free(utfname); gchar *tinfo = g_locale_to_utf8("tEXt::Source", -1, NULL, &i, NULL); gchar *tinfo2 = g_locale_to_utf8("Saved by libcrn.", -1, NULL, &i, NULL); bool ok = gdk_pixbuf_save(pb, filename, "png", &err, tinfo, tinfo2, NULL); g_free(filename); g_free(tinfo); g_free(tinfo2); g_object_unref(pb); String out(U""); if (!ok) { out = String(_("Cannot save file. ")) + err->message; g_error_free(err); } return std::make_pair(ok, out); }
static std::pair<bool, String> save_png_libpng(const Path &filename, const ImageRGB &img) { // libpng does not support URIs Path fname(filename); fname.ToLocal(); std::unique_ptr<FILE, decltype(fclose_if_not_null)*> fp(fopen(fname.CStr(), "wb"), fclose_if_not_null); if (!fp) { return std::make_pair(false, String(_("Cannot create file ")) + U"<" + fname + U">"); } /* Create png struct & info */ png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return std::make_pair(false, String(_("Cannot create the PNG structure."))); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return std::make_pair(false, String(_("Cannot create the PNG info."))); } /* Set up the error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return std::make_pair(false, String(_("Error while generating the PNG image."))); } /* setup libpng for using standard C fwrite() function with our FILE pointer */ png_init_io(png_ptr, fp.get()); /* Fill in the png_info structure */ int width = int(img.GetWidth()); int height = int(img.GetHeight()); int bit_depth = 8; int color_type = PNG_COLOR_TYPE_RGB; int interlace_type = PNG_INTERLACE_NONE; int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; int filter_method = PNG_FILTER_TYPE_DEFAULT; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_method); /* Using the low-level write interface */ png_write_info(png_ptr, info_ptr); png_bytepp row_pointers; row_pointers = (png_bytep*)malloc(sizeof(png_byte*) * height); for (int i = 0; i < height ; ++i) { #if (PNG_LIBPNG_VER > 10300) row_pointers[i] = (png_bytep)calloc(1, png_get_rowbytes(png_ptr, info_ptr)); #else row_pointers[i] = (png_bytep)calloc(1, info_ptr->rowbytes); #endif } /* Conversion */ #if (PNG_LIBPNG_VER > 10300) int channels = png_get_channels(png_ptr, info_ptr); #else int channels = info_ptr->channels; #endif for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { const auto px = img.At(x, y); row_pointers[y][x * channels] = px.r; row_pointers[y][x * channels + 1] = px.g; row_pointers[y][x * channels + 2] = px.b; } png_write_image(png_ptr, row_pointers); // TODO more options png_text txt[1]; txt[0].compression = PNG_TEXT_COMPRESSION_NONE; txt[0].key = (char*)"creator"; txt[0].text = (char*)"libcrn"; txt[0].text_length = strlen(txt[0].text); png_set_text(png_ptr, info_ptr, txt, 1); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); // free for (int i = 0; i < height ; ++i) { free(row_pointers[i]); } free(row_pointers); return std::make_pair(true, String("")); }