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
5 #include "CImageWriterJPG.h"
\r
7 #ifdef _IRR_COMPILE_WITH_JPG_WRITER_
\r
9 #include "CColorConverter.h"
\r
10 #include "IWriteFile.h"
\r
12 #include "irrString.h"
\r
15 #ifdef _IRR_COMPILE_WITH_LIBJPEG_
\r
16 #include <stdio.h> // required for jpeglib.h
\r
19 #ifndef _IRR_USE_NON_SYSTEM_JPEG_LIB_
\r
20 #include <jpeglib.h>
\r
23 #include "jpeglib/jpeglib.h"
\r
24 #include "jpeglib/jerror.h"
\r
34 // The writer uses a 4k buffer and flushes to disk each time it's filled
\r
35 #define OUTPUT_BUF_SIZE 4096
\r
38 struct jpeg_destination_mgr pub;/* public fields */
\r
40 io::IWriteFile* file; /* target file */
\r
41 JOCTET buffer[OUTPUT_BUF_SIZE]; /* image buffer */
\r
42 } mem_destination_mgr;
\r
45 typedef mem_destination_mgr * mem_dest_ptr;
\r
49 static void jpeg_init_destination(j_compress_ptr cinfo)
\r
51 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
\r
52 dest->pub.next_output_byte = dest->buffer;
\r
53 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
\r
57 // flush to disk and reset buffer
\r
58 static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
\r
60 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
\r
62 // for now just exit upon file error
\r
63 if (dest->file->write(dest->buffer, OUTPUT_BUF_SIZE) != OUTPUT_BUF_SIZE)
\r
64 ERREXIT (cinfo, JERR_FILE_WRITE);
\r
66 dest->pub.next_output_byte = dest->buffer;
\r
67 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
\r
73 static void jpeg_term_destination(j_compress_ptr cinfo)
\r
75 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
\r
76 const size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
\r
77 // for now just exit upon file error
\r
78 if (dest->file->write(dest->buffer, datacount) != datacount)
\r
79 ERREXIT (cinfo, JERR_FILE_WRITE);
\r
83 // set up buffer data
\r
84 static void jpeg_file_dest(j_compress_ptr cinfo, io::IWriteFile* file)
\r
86 if (cinfo->dest == NULL)
\r
87 { /* first time for this JPEG object? */
\r
88 cinfo->dest = (struct jpeg_destination_mgr *)
\r
89 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
\r
91 sizeof(mem_destination_mgr));
\r
94 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; /* for casting */
\r
96 /* Initialize method pointers */
\r
97 dest->pub.init_destination = jpeg_init_destination;
\r
98 dest->pub.empty_output_buffer = jpeg_empty_output_buffer;
\r
99 dest->pub.term_destination = jpeg_term_destination;
\r
101 /* Initialize private member */
\r
106 /* write_JPEG_memory: store JPEG compressed image into memory.
\r
108 static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality)
\r
110 void (*format)(const void*, s32, void*) = 0;
\r
111 switch( image->getColorFormat () )
\r
114 format = CColorConverter::convert_R8G8B8toR8G8B8;
\r
117 format = CColorConverter::convert_A8R8G8B8toR8G8B8;
\r
120 format = CColorConverter::convert_A1R5G5B5toB8G8R8;
\r
123 format = CColorConverter::convert_R5G6B5toR8G8B8;
\r
126 os::Printer::log("writeJPEGFile does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING);
\r
130 // couldn't find a color converter
\r
134 const core::dimension2du dim = image->getDimension();
\r
136 struct jpeg_compress_struct cinfo;
\r
137 struct jpeg_error_mgr jerr;
\r
138 cinfo.err = jpeg_std_error(&jerr);
\r
140 jpeg_create_compress(&cinfo);
\r
141 jpeg_file_dest(&cinfo, file);
\r
142 cinfo.image_width = dim.Width;
\r
143 cinfo.image_height = dim.Height;
\r
144 cinfo.input_components = 3;
\r
145 cinfo.in_color_space = JCS_RGB;
\r
147 jpeg_set_defaults(&cinfo);
\r
149 if ( 0 == quality )
\r
152 jpeg_set_quality(&cinfo, quality, TRUE);
\r
153 jpeg_start_compress(&cinfo, TRUE);
\r
155 u8 * dest = new u8[dim.Width*3];
\r
159 const u32 pitch = image->getPitch();
\r
160 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
\r
161 row_pointer[0] = dest;
\r
163 u8* src = (u8*)image->getData();
\r
165 while (cinfo.next_scanline < cinfo.image_height)
\r
167 // convert next line
\r
168 format( src, dim.Width, dest );
\r
170 jpeg_write_scanlines(&cinfo, row_pointer, 1);
\r
175 /* Step 6: Finish compression */
\r
176 jpeg_finish_compress(&cinfo);
\r
179 /* Step 7: Destroy */
\r
180 jpeg_destroy_compress(&cinfo);
\r
182 return (dest != 0);
\r
186 } // namespace video
\r
189 #endif // _IRR_COMPILE_WITH_LIBJPEG_
\r
196 IImageWriter* createImageWriterJPG()
\r
198 return new CImageWriterJPG;
\r
201 CImageWriterJPG::CImageWriterJPG()
\r
204 setDebugName("CImageWriterJPG");
\r
209 bool CImageWriterJPG::isAWriteableFileExtension(const io::path& filename) const
\r
211 return core::hasFileExtension ( filename, "jpg", "jpeg" );
\r
215 bool CImageWriterJPG::writeImage(io::IWriteFile *file, IImage *image, u32 quality) const
\r
217 #ifndef _IRR_COMPILE_WITH_LIBJPEG_
\r
220 return writeJPEGFile(file, image, quality);
\r
224 } // namespace video
\r