Update procedures
[shapes.git] / source / import_jpeg.cc
blob86780331e37e5d89a5b25596082ac18ad34565e4
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2009 Henrik Tidefelt
19 #include "drawabletypes.h"
20 #include "rasterloaders.h"
21 #include "statetypes.h"
22 #include "globals.h"
23 #include "consts.h"
24 #include "config.h"
26 #include <fstream>
27 #include <cstdio>
29 using namespace Shapes;
32 #ifdef HAVE_LIBJPEG
34 /* Since jpeglib.h includes jconfig.h, which contains #defines that are in conflict with our own #defines.
35 * Note that it is necessary to include config.h before jpeglib.h, becase it is only after config.h has been
36 * included that we can tell whether jpeglib.h should be included at all.
38 #undef HAVE_STDDEF_H
39 #undef HAVE_STDLIB_H
40 #include <jpeglib.h>
42 namespace Shapes
44 namespace Kernel
47 struct Shapes_jpeglib_error_mgr : public jpeg_error_mgr
49 const char * filename_;
52 void
53 Shapes_jpeglib_exit( j_common_ptr cinfo )
55 char buf[ JMSG_LENGTH_MAX ];
56 (*cinfo->err->format_message)( cinfo, buf );
57 std::ostringstream msg;
58 msg << "There was a problem importing the JPEG file " << reinterpret_cast< Shapes_jpeglib_error_mgr * >( cinfo->err )->filename_ << ": " << buf ;
59 throw Exceptions::ExternalError( strrefdup( msg ) );
64 #endif
67 RefCountPtr< const Lang::RasterImage >
68 Shapes::Helpers::RasterLoader_JPEG::load( RefCountPtr< std::ifstream > & filePtr, const std::string & full_filename, Concrete::Length resolution, bool override, const Ast::PlacedIdentifier & coreId, const Ast::SourceLocation & callLoc ) const
70 #ifndef HAVE_LIBJPEG
71 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_LIBJPEG, coreId, callLoc );
72 #else
74 /* The library seems incompatible with c++ istream sources, so we close the stream and do it the old way instead.
76 filePtr->close( );
77 FILE * iFile = fopen( full_filename.c_str( ), "rb" );
78 if( iFile == 0 )
80 std::ostringstream msg;
81 msg << "The file " << full_filename << " was found, but could not be opened for read." ;
82 throw Exceptions::ExternalError( strrefdup( msg ) );
85 struct jpeg_decompress_struct cinfo;
86 Kernel::Shapes_jpeglib_error_mgr jerr;
88 /* Step 1: allocate and initialize JPEG decompression object */
90 /* We set up the normal JPEG error routines, then override error_exit. */
91 cinfo.err = jpeg_std_error( & jerr );
92 jerr.error_exit = Kernel::Shapes_jpeglib_exit;
93 jerr.filename_ = full_filename.c_str( );
94 /* Establish the setjmp return context for my_error_exit to use. */
95 try
97 /* Now we can initialize the JPEG decompression object. */
98 jpeg_create_decompress( & cinfo );
99 jpeg_stdio_src( & cinfo, iFile );
100 (void) jpeg_read_header( & cinfo, TRUE );
101 (void) jpeg_start_decompress( & cinfo );
103 Concrete::Length resolution_x = resolution;
104 Concrete::Length resolution_y = resolution;
105 if( ! override )
107 switch( cinfo.density_unit )
109 case 0:/* Only aspect ratio. */
111 Concrete::Length tmpRes = sqrt( static_cast< double >( cinfo.X_density ) * static_cast< double >( cinfo.Y_density ) ) * resolution;
112 resolution_x = ( tmpRes / cinfo.X_density );
113 resolution_y = ( tmpRes / cinfo.Y_density );
115 break;
116 case 1:/* Dots per inch. */
118 resolution_x = ( Concrete::Length( 72. ) / cinfo.X_density );
119 resolution_y = ( Concrete::Length( 72. ) / cinfo.Y_density );
121 break;
122 case 2:/* Dots per centimeter. */
124 resolution_x = ( Concrete::Length( 72. / 2.54 ) / cinfo.X_density );
125 resolution_y = ( Concrete::Length( 72. / 2.54 ) / cinfo.Y_density );
127 break;
128 default:
129 throw Exceptions::CoreRequirement( "The JPEG file was using an unknown density unit value.", coreId, callLoc );
132 size_t size_x = cinfo.image_width;
133 size_t size_y = cinfo.image_height;
134 size_t size_depth = 8; /* Always 8 for JPEG, according to the "PDF Reference, fifth edition", section 3.3.7 ("DCTDeccode Filter"). */
136 RefCountPtr< const Lang::ColorSpace > colorSpace = Lang::THE_COLOR_SPACE_DEVICE_RGB;
137 int colorConversion = 0; /* This flag allows some unusual colorspaces of JPEG to be treated as ordinary RGB or CMYK. */
138 switch( cinfo.jpeg_color_space )
140 case JCS_UNKNOWN: /* error/unspecified */
141 throw Exceptions::CoreRequirement( "The color space was unspecified in the JPEG file.", coreId, callLoc );
142 case JCS_GRAYSCALE: /* monochrome */
143 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_GRAY;
144 colorConversion = 0;
145 break;
146 case JCS_RGB: /* red/green/blue */
147 /* Use the default value set above! */
148 break;
149 case JCS_YCbCr: /* Y/Cb/Cr (also known as YUV) */
150 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_RGB;
151 colorConversion = 1;
152 break;
153 case JCS_CMYK: /* C/M/Y/K */
154 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_CMYK;
155 colorConversion = 0;
156 break;
157 case JCS_YCCK: /* Y/Cb/Cr/K */
158 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_CMYK;
159 colorConversion = 1;
160 break;
161 default:
162 throw Exceptions::CoreRequirement( "The JPEG file was using an unknown color type value.", coreId, callLoc );
165 Lang::RasterImage * imagePtr = Lang::RasterImage::newInstance( size_x, size_y, size_depth, resolution_x, resolution_y, colorSpace );
166 RefCountPtr< const Lang::RasterImage > image = RefCountPtr< const Lang::RasterImage >( RefCountPtr< const Lang::RasterImage >( imagePtr ) );
168 SimplePDF::PDF_Stream_out & stream = *(imagePtr->stream( ));
169 stream[ "Filter" ] = SimplePDF::newName( "DCTDecode" );
170 /* The default value for the ColorTransform depends on the number of components in the color space. */
171 if( ( colorConversion != 1 && colorSpace->numberOfComponents( ) == 3 ) ||
172 ( colorConversion != 0 && colorSpace->numberOfComponents( ) != 3 ) )
174 stream[ "ColorTransform" ] = SimplePDF::newInt( colorConversion );
176 stream.invertFilterOnWrite = false;
178 std::fseek( iFile, 0, SEEK_END );
179 const size_t filesize = std::ftell( iFile );
180 std::rewind( iFile );
181 RefCountPtr< char > buf = RefCountPtr< char >( new char[ filesize ] );
182 if( fread( buf.getPtr( ), 1, filesize, iFile ) != filesize )
184 throw Exceptions::ExternalError( "Failed to read JPEG file content into memory." );
186 stream.data.write( buf.getPtr( ), filesize );
188 /* If everything was OK, we just free allocated resources and return.
190 jpeg_destroy_decompress( & cinfo );
191 fclose( iFile );
193 return image;
196 catch( const Exceptions::Exception & ball )
198 jpeg_destroy_decompress( & cinfo );
199 fclose( iFile );
200 throw;
202 #endif