Canola  0.8.D001
lib/image/format/jpeg.cc
Go to the documentation of this file.
00001 //
00002 // canola - canon canola 1614p emulator
00003 // Copyright (C) 2011 Peter Miller
00004 //
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License, version 3, as
00007 // published by the Free Software Foundation.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program. If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include <lib/ac/stdio.h>
00019 #include <lib/ac/string.h>
00020 #include <libexplain/fclose.h>
00021 #include <libexplain/fopen.h>
00022 #include <jpeglib.h>
00023 
00024 #include <lib/image/format/jpeg.h>
00025 
00026 
00027 image_format_jpeg::~image_format_jpeg()
00028 {
00029 }
00030 
00031 
00032 image_format_jpeg::image_format_jpeg(int a_width, int a_height) :
00033     image_format(a_width, a_height)
00034 {
00035 }
00036 
00037 
00038 image_format_jpeg::image_format_jpeg(
00039     int a_width,
00040     int a_height,
00041     data_t *a_data
00042 ) :
00043     image_format(a_width, a_height, a_data)
00044 {
00045 }
00046 
00047 
00048 const char *
00049 image_format_jpeg::type_name(void)
00050     const
00051 {
00052     return "JPEG";
00053 }
00054 
00055 
00056 image::pointer
00057 image_format_jpeg::create(const std::string &filename)
00058 {
00059     jpeg_decompress_struct cinfo;
00060     jpeg_error_mgr jerr;
00061     cinfo.err = jpeg_std_error(&jerr);
00062     jpeg_create_decompress(&cinfo);
00063 
00064     //
00065     // tell the jpeg library where to get its input from
00066     //
00067     FILE *fp = explain_fopen_or_die(filename.c_str(), "rb");
00068     jpeg_stdio_src(&cinfo, fp);
00069 
00070     //
00071     // read the file header
00072     //
00073     jpeg_read_header(&cinfo, TRUE);
00074 
00075     // tell the decompress we want RGB data
00076     cinfo.out_color_space = JCS_RGB;
00077     cinfo.quantize_colors = false;
00078 
00079     jpeg_start_decompress(&cinfo);
00080     int width = cinfo.output_width;
00081     int height = cinfo.output_height;
00082 
00083     size_t rgba_row_stride = width * 4;
00084     size_t rgba_data_size = height * rgba_row_stride;
00085     data_t *rgba_data = new data_t [rgba_data_size];
00086 
00087     int row_stride = width * cinfo.output_components;
00088     JSAMPLE *buffer = new JSAMPLE [row_stride];
00089 
00090     for (int y = 0; y < height; ++y)
00091     {
00092         //
00093         // jpeg_read_scanlines expects an array of pointers to scanlines.
00094         // Here the array is only one element long, but you could ask for
00095         // more than one scanline at a time if that's more convenient.
00096         //
00097         jpeg_read_scanlines(&cinfo, &buffer, 1);
00098 
00099         //
00100         // Transfer the RGB row into an RGBA row
00101         //
00102         JSAMPLE *ip = buffer;
00103         data_t *op = rgba_data + y * rgba_row_stride;
00104         for (int x = 0; x < width; ++x)
00105         {
00106             *op++ = *ip++;
00107             *op++ = *ip++;
00108             *op++ = *ip++;
00109             *op++ = 255;
00110         }
00111     }
00112     delete buffer;
00113 
00114     //
00115     // All done, release the resources.
00116     //
00117     jpeg_finish_decompress(&cinfo);
00118     explain_fclose_or_die(fp);
00119 
00120     //
00121     // Create the object.
00122     //
00123     return pointer(new image_format_jpeg(width, height, rgba_data));
00124 }
00125 
00126 
00127 void
00128 image_format_jpeg::save_to_file(const std::string &filename)
00129     const
00130 {
00131     //
00132     // create file
00133     //
00134     FILE *fp = explain_fopen_or_die(filename.c_str(), "wb");
00135 
00136     jpeg_compress_struct cinfo;
00137     memset(&cinfo, 0, sizeof(cinfo));
00138     jpeg_error_mgr jerr;
00139     memset(&jerr, 0, sizeof(jerr));
00140     cinfo.err = jpeg_std_error(&jerr);
00141     jpeg_create_compress(&cinfo);
00142     jpeg_stdio_dest(&cinfo, fp);
00143     cinfo.image_width = get_width();
00144     cinfo.image_height = get_height();
00145     cinfo.input_components = 3;
00146     cinfo.in_color_space = JCS_RGB;
00147     jpeg_set_defaults(&cinfo);
00148     jpeg_set_quality(&cinfo, 100, 1);
00149     jpeg_start_compress(&cinfo, 1);
00150 
00151     //
00152     // Write each scan line, one at a time
00153     JSAMPLE *rowbuf = new JSAMPLE [cinfo.image_width * 3];
00154     while (cinfo.next_scanline < cinfo.image_height)
00155     {
00156         const data_t *ip = get_data(cinfo.next_scanline);
00157         JSAMPLE *op = rowbuf;
00158         for (size_t x = 0; x < cinfo.image_width; ++x)
00159         {
00160             // turn RGBA data into RGB data
00161             *op++ = *ip++;
00162             *op++ = *ip++;
00163             *op++ = *ip++;
00164             ++ip;
00165         }
00166         jpeg_write_scanlines(&cinfo, &rowbuf, 1);
00167     }
00168     delete rowbuf;
00169     jpeg_finish_compress(&cinfo);
00170     jpeg_destroy_compress(&cinfo);
00171 
00172     explain_fclose_or_die(fp);
00173 }
00174 
00175 
00176 image::pointer
00177 image_format_jpeg::create_blank(int width, int height)
00178 {
00179     return pointer(new image_format_jpeg(width, height));
00180 }