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
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"
29 using namespace Shapes
;
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.
47 struct Shapes_jpeglib_error_mgr
: public jpeg_error_mgr
49 const char * filename_
;
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
) );
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 char * core_title
, const Ast::SourceLocation
& callLoc
) const
71 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_LIBJPEG
, core_title
, callLoc
);
74 /* The library seems incompatible with c++ istream sources, so we close the stream and do it the old way instead.
77 FILE * iFile
= fopen( full_filename
.c_str( ), "rb" );
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. */
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
;
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
);
116 case 1:/* Dots per inch. */
118 resolution_x
= ( Concrete::Length( 72. ) / cinfo
.X_density
);
119 resolution_y
= ( Concrete::Length( 72. ) / cinfo
.Y_density
);
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
);
129 throw Exceptions::CoreRequirement( "The JPEG file was using an unknown density unit value.", core_title
, 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.", core_title
, callLoc
);
142 case JCS_GRAYSCALE
: /* monochrome */
143 colorSpace
= Lang::THE_COLOR_SPACE_DEVICE_GRAY
;
146 case JCS_RGB
: /* red/green/blue */
147 /* Use the default value set above! */
149 case JCS_YCbCr
: /* Y/Cb/Cr (also known as YUV) */
150 colorSpace
= Lang::THE_COLOR_SPACE_DEVICE_RGB
;
153 case JCS_CMYK
: /* C/M/Y/K */
154 colorSpace
= Lang::THE_COLOR_SPACE_DEVICE_CMYK
;
157 case JCS_YCCK
: /* Y/Cb/Cr/K */
158 colorSpace
= Lang::THE_COLOR_SPACE_DEVICE_CMYK
;
162 throw Exceptions::CoreRequirement( "The JPEG file was using an unknown color type value.", core_title
, 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
);
196 catch( const Exceptions::Exception
& ball
)
198 jpeg_destroy_decompress( & cinfo
);