static bool convert_file (const std::string &in_filename, const std::string &out_filename) { if (noclobber && Filesystem::exists(out_filename)) { std::cerr << "iconvert ERROR: Output file already exists \"" << out_filename << "\"\n"; return false; } if (verbose) std::cout << "Converting " << in_filename << " to " << out_filename << "\n"; std::string tempname = out_filename; if (tempname == in_filename) { tempname = out_filename + ".tmp" + Filesystem::extension (out_filename); } // Find an ImageIO plugin that can open the input file, and open it. ImageInput *in = ImageInput::open (in_filename.c_str()); if (! in) { std::string err = geterror(); std::cerr << "iconvert ERROR: " << (err.length() ? err : Strutil::format("Could not open \"%s\"", in_filename)) << "\n"; delete in; return false; } ImageSpec inspec = in->spec(); std::string metadatatime = inspec.get_string_attribute ("DateTime"); // Find an ImageIO plugin that can open the output file, and open it ImageOutput *out = ImageOutput::create (tempname.c_str()); if (! out) { std::cerr << "iconvert ERROR: Could not find an ImageIO plugin to write \"" << out_filename << "\" :" << geterror() << "\n"; delete in; return false; } // In order to deal with formats that support subimages, but not // subimage appending, we gather them all first. std::vector<ImageSpec> subimagespecs; if (out->supports("multiimage") && !out->supports("appendsubimage")) { ImageCache *imagecache = ImageCache::create (); int nsubimages = 0; ustring ufilename (in_filename); imagecache->get_image_info (ufilename, 0, 0, ustring("subimages"), TypeDesc::TypeInt, &nsubimages); if (nsubimages > 1) { subimagespecs.resize (nsubimages); for (int i = 0; i < nsubimages; ++i) { ImageSpec inspec = *imagecache->imagespec (ufilename, i, 0, true /*native*/); subimagespecs[i] = inspec; adjust_spec (in, out, inspec, subimagespecs[i]); } } ImageCache::destroy (imagecache); } bool ok = true; bool mip_to_subimage_warning = false; for (int subimage = 0; ok && in->seek_subimage(subimage,0,inspec); ++subimage) { if (subimage > 0 && !out->supports ("multiimage")) { std::cerr << "iconvert WARNING: " << out->format_name() << " does not support multiple subimages.\n"; std::cerr << "\tOnly the first subimage has been copied.\n"; break; // we're done } int miplevel = 0; do { // Copy the spec, with possible change in format ImageSpec outspec = inspec; bool nocopy = adjust_spec (in, out, inspec, outspec); if (miplevel > 0) { // Moving to next MIP level ImageOutput::OpenMode mode; if (out->supports ("mipmap")) mode = ImageOutput::AppendMIPLevel; else if (out->supports ("multiimage") && out->supports ("appendsubimage")) { mode = ImageOutput::AppendSubimage; // use if we must if (! mip_to_subimage_warning && strcmp(out->format_name(),"tiff")) { std::cerr << "iconvert WARNING: " << out->format_name() << " does not support MIPmaps.\n"; std::cerr << "\tStoring the MIPmap levels in subimages.\n"; } mip_to_subimage_warning = true; } else { std::cerr << "iconvert WARNING: " << out->format_name() << " does not support MIPmaps.\n"; std::cerr << "\tOnly the first level has been copied.\n"; break; // on to the next subimage } ok = out->open (tempname.c_str(), outspec, mode); } else if (subimage > 0) { // Moving to next subimage ok = out->open (tempname.c_str(), outspec, ImageOutput::AppendSubimage); } else { // First time opening if (subimagespecs.size()) ok = out->open (tempname.c_str(), int(subimagespecs.size()), &subimagespecs[0]); else ok = out->open (tempname.c_str(), outspec, ImageOutput::Create); } if (! ok) { std::string err = out->geterror(); std::cerr << "iconvert ERROR: " << (err.length() ? err : Strutil::format("Could not open \"%s\"", out_filename)) << "\n"; ok = false; break; } if (! nocopy) { ok = out->copy_image (in); if (! ok) std::cerr << "iconvert ERROR copying \"" << in_filename << "\" to \"" << out_filename << "\" :\n\t" << out->geterror() << "\n"; } else { // Need to do it by hand for some reason. Future expansion in which // only a subset of channels are copied, or some such. std::vector<char> pixels ((size_t)outspec.image_bytes(true)); ok = in->read_image (outspec.format, &pixels[0]); if (! ok) { std::cerr << "iconvert ERROR reading \"" << in_filename << "\" : " << in->geterror() << "\n"; } else { ok = out->write_image (outspec.format, &pixels[0]); if (! ok) std::cerr << "iconvert ERROR writing \"" << out_filename << "\" : " << out->geterror() << "\n"; } } ++miplevel; } while (ok && in->seek_subimage(subimage,miplevel,inspec)); } out->close (); delete out; in->close (); delete in; // Figure out a time for the input file -- either one supplied by // the metadata, or the actual time stamp of the input file. std::time_t in_time; if (metadatatime.empty() || ! DateTime_to_time_t (metadatatime.c_str(), in_time)) in_time = Filesystem::last_write_time (in_filename); if (out_filename != tempname) { if (ok) { Filesystem::remove (out_filename); Filesystem::rename (tempname, out_filename); } else Filesystem::remove (tempname); } // If user requested, try to adjust the file's modification time to // the creation time indicated by the file's DateTime metadata. if (ok && adjust_time) Filesystem::last_write_time (out_filename, in_time); return ok; }