]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CImageWriterJPG.cpp
Remove bundled libraries
[irrlicht.git] / source / Irrlicht / CImageWriterJPG.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CImageWriterJPG.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_JPG_WRITER_\r
8 \r
9 #include "CColorConverter.h"\r
10 #include "IWriteFile.h"\r
11 #include "CImage.h"\r
12 #include "irrString.h"\r
13 #include "os.h"\r
14 \r
15 #ifdef _IRR_COMPILE_WITH_LIBJPEG_\r
16 #include <stdio.h> // required for jpeglib.h\r
17 extern "C"\r
18 {\r
19         #include <jpeglib.h>\r
20         #include <jerror.h>\r
21 }\r
22 \r
23 \r
24 namespace irr\r
25 {\r
26 namespace video\r
27 {\r
28 \r
29 // The writer uses a 4k buffer and flushes to disk each time it's filled\r
30 #define OUTPUT_BUF_SIZE 4096\r
31 typedef struct\r
32 {\r
33         struct jpeg_destination_mgr pub;/* public fields */\r
34 \r
35         io::IWriteFile* file;           /* target file */\r
36         JOCTET buffer[OUTPUT_BUF_SIZE]; /* image buffer */\r
37 } mem_destination_mgr;\r
38 \r
39 \r
40 typedef mem_destination_mgr * mem_dest_ptr;\r
41 \r
42 \r
43 // init\r
44 static void jpeg_init_destination(j_compress_ptr cinfo)\r
45 {\r
46         mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;\r
47         dest->pub.next_output_byte = dest->buffer;\r
48         dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;\r
49 }\r
50 \r
51 \r
52 // flush to disk and reset buffer\r
53 static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)\r
54 {\r
55         mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;\r
56 \r
57         // for now just exit upon file error\r
58         if (dest->file->write(dest->buffer, OUTPUT_BUF_SIZE) != OUTPUT_BUF_SIZE)\r
59                 ERREXIT (cinfo, JERR_FILE_WRITE);\r
60 \r
61         dest->pub.next_output_byte = dest->buffer;\r
62         dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;\r
63 \r
64         return TRUE;\r
65 }\r
66 \r
67 \r
68 static void jpeg_term_destination(j_compress_ptr cinfo)\r
69 {\r
70         mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;\r
71         const size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;\r
72         // for now just exit upon file error\r
73         if (dest->file->write(dest->buffer, datacount) != datacount)\r
74                 ERREXIT (cinfo, JERR_FILE_WRITE);\r
75 }\r
76 \r
77 \r
78 // set up buffer data\r
79 static void jpeg_file_dest(j_compress_ptr cinfo, io::IWriteFile* file)\r
80 {\r
81         if (cinfo->dest == NULL)\r
82         { /* first time for this JPEG object? */\r
83                 cinfo->dest = (struct jpeg_destination_mgr *)\r
84                         (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,\r
85                                                 JPOOL_PERMANENT,\r
86                                                 sizeof(mem_destination_mgr));\r
87         }\r
88 \r
89         mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;  /* for casting */\r
90 \r
91         /* Initialize method pointers */\r
92         dest->pub.init_destination = jpeg_init_destination;\r
93         dest->pub.empty_output_buffer = jpeg_empty_output_buffer;\r
94         dest->pub.term_destination = jpeg_term_destination;\r
95 \r
96         /* Initialize private member */\r
97         dest->file = file;\r
98 }\r
99 \r
100 \r
101 /* write_JPEG_memory: store JPEG compressed image into memory.\r
102 */\r
103 static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality)\r
104 {\r
105         void (*format)(const void*, s32, void*) = 0;\r
106         switch( image->getColorFormat () )\r
107         {\r
108                 case ECF_R8G8B8:\r
109                         format = CColorConverter::convert_R8G8B8toR8G8B8;\r
110                         break;\r
111                 case ECF_A8R8G8B8:\r
112                         format = CColorConverter::convert_A8R8G8B8toR8G8B8;\r
113                         break;\r
114                 case ECF_A1R5G5B5:\r
115                         format = CColorConverter::convert_A1R5G5B5toB8G8R8;\r
116                         break;\r
117                 case ECF_R5G6B5:\r
118                         format = CColorConverter::convert_R5G6B5toR8G8B8;\r
119                         break;\r
120                 default:\r
121                         os::Printer::log("writeJPEGFile does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING);\r
122                         break;\r
123         }\r
124 \r
125         // couldn't find a color converter\r
126         if ( 0 == format )\r
127                 return false;\r
128 \r
129         const core::dimension2du dim = image->getDimension();\r
130 \r
131         struct jpeg_compress_struct cinfo;\r
132         struct jpeg_error_mgr jerr;\r
133         cinfo.err = jpeg_std_error(&jerr);\r
134 \r
135         jpeg_create_compress(&cinfo);\r
136         jpeg_file_dest(&cinfo, file);\r
137         cinfo.image_width = dim.Width;\r
138         cinfo.image_height = dim.Height;\r
139         cinfo.input_components = 3;\r
140         cinfo.in_color_space = JCS_RGB;\r
141 \r
142         jpeg_set_defaults(&cinfo);\r
143 \r
144         if ( 0 == quality )\r
145                 quality = 75;\r
146 \r
147         jpeg_set_quality(&cinfo, quality, TRUE);\r
148         jpeg_start_compress(&cinfo, TRUE);\r
149 \r
150         u8 * dest = new u8[dim.Width*3];\r
151 \r
152         if (dest)\r
153         {\r
154                 const u32 pitch = image->getPitch();\r
155                 JSAMPROW row_pointer[1];      /* pointer to JSAMPLE row[s] */\r
156                 row_pointer[0] = dest;\r
157 \r
158                 u8* src = (u8*)image->getData();\r
159 \r
160                 while (cinfo.next_scanline < cinfo.image_height)\r
161                 {\r
162                         // convert next line\r
163                         format( src, dim.Width, dest );\r
164                         src += pitch;\r
165                         jpeg_write_scanlines(&cinfo, row_pointer, 1);\r
166                 }\r
167 \r
168                 delete [] dest;\r
169 \r
170                 /* Step 6: Finish compression */\r
171                 jpeg_finish_compress(&cinfo);\r
172         }\r
173 \r
174         /* Step 7: Destroy */\r
175         jpeg_destroy_compress(&cinfo);\r
176 \r
177         return (dest != 0);\r
178 }\r
179 \r
180 \r
181 } // namespace video\r
182 } // namespace irr\r
183 \r
184 #endif // _IRR_COMPILE_WITH_LIBJPEG_\r
185 \r
186 namespace irr\r
187 {\r
188 namespace video\r
189 {\r
190 \r
191 IImageWriter* createImageWriterJPG()\r
192 {\r
193         return new CImageWriterJPG;\r
194 }\r
195 \r
196 CImageWriterJPG::CImageWriterJPG()\r
197 {\r
198 #ifdef _DEBUG\r
199         setDebugName("CImageWriterJPG");\r
200 #endif\r
201 }\r
202 \r
203 \r
204 bool CImageWriterJPG::isAWriteableFileExtension(const io::path& filename) const\r
205 {\r
206         return core::hasFileExtension ( filename, "jpg", "jpeg" );\r
207 }\r
208 \r
209 \r
210 bool CImageWriterJPG::writeImage(io::IWriteFile *file, IImage *image, u32 quality) const\r
211 {\r
212 #ifndef _IRR_COMPILE_WITH_LIBJPEG_\r
213         return false;\r
214 #else\r
215         return writeJPEGFile(file, image, quality);\r
216 #endif\r
217 }\r
218 \r
219 } // namespace video\r
220 } // namespace irr\r
221 \r
222 #endif\r
223 \r