// jpegWriter.C // Copyright (c) 2009 The Foundry Visionmongers Ltd. All Rights Reserved. // Write jpeg JFIF files. This is an example of a file writer that uses // a separate library. It also reuses the FILE opened by FileWriter but // none of it's read/write methods. The reason it uses a FileWriter is // to handle the complexity of Windoze driver letters and the use of a // temporary output file. #include extern "C" { #include "jpeg.h" } #include "DDImage/FileWriter.h" #include "DDImage/Row.h" #include "DDImage/ARRAY.h" #include "exifWriter.h" static struct jpeg_error_mgr jerr; using namespace DD::Image; class jpegWriter : public ExifWriter { struct jpeg_compress_struct cinfo; float quality; public: jpegWriter(Write* iop) : ExifWriter(iop) { cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); quality = .75f; } ~jpegWriter() { jpeg_destroy_compress(&cinfo); } void execute(); void knobs(Knob_Callback); static const Writer::Description d; const char* help() { return "jpeg"; } }; static Writer* build(Write* iop) { return new jpegWriter(iop); } const Writer::Description jpegWriter::d("jpeg\0jpg\0", build); void jpegWriter::execute() { if (!open()) return; bool mono = num_channels() <= 1; ChannelSet channels = channel_mask(mono ? 1 : 3); input0().request(0, 0, width(), height(), channels, 1); jpeg_stdio_dest(&cinfo, (FILE*)file); cinfo.image_width = width(); cinfo.image_height = height(); if (!mono) { cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } else { cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; } jpeg_set_defaults(&cinfo); cinfo.Y_density = 1200; cinfo.X_density = (UINT16)(iop->format().pixel_aspect() * cinfo.Y_density + .5); jpeg_set_quality(&cinfo, fast_rint(quality * 100), FALSE); jpeg_start_compress(&cinfo, TRUE); ExifData* exif = makeExifData(); unsigned char* data; unsigned int data_size; exif_data_save_data(exif, &data, &data_size); jpeg_write_marker(&cinfo, JPEG_APP0 + 1, data, data_size); exif_data_free(exif); ARRAY(uchar, buffer, cinfo.input_components * cinfo.image_width); unsigned char* arrayp = &buffer[0]; Row row(0, width()); for (int y = 0; y < height(); y++) { iop->status(double(y) / height()); get(height() - y - 1, 0, width(), channels, row); if (aborted()) { jpeg_destroy_compress(&cinfo); jpeg_create_compress(&cinfo); return; } for (int i = 0; i < cinfo.input_components; i++) to_byte(i, buffer + i, row[channel(i)], 0, width(), cinfo.input_components); jpeg_write_scanlines(&cinfo, &arrayp, 1); } jpeg_finish_compress(&cinfo); close(); } #include "DDImage/Knobs.h" void jpegWriter::knobs(Knob_Callback f) { Float_knob(f, &quality, "_jpeg_quality", "quality"); }