The exact commands to make this commit were: git reset --hard origin/master find -type f | # list all regular files grep -E '\.(h|cpp|fsh|vsh|mm)|LICENSE$' | # filter for text files xargs -n 1 -P $(nproc) sed -i 's:\s*$::' # for each file, trim trailing whitespace including the CR git commit -a
		
			
				
	
	
		
			214 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 Nikolaus Gebhardt
 | |
| // This file is part of the "Irrlicht Engine".
 | |
| // For conditions of distribution and use, see copyright notice in irrlicht.h
 | |
| 
 | |
| #include "CImageWriterJPG.h"
 | |
| 
 | |
| #include "CColorConverter.h"
 | |
| #include "IWriteFile.h"
 | |
| #include "CImage.h"
 | |
| #include "irrString.h"
 | |
| #include "os.h"
 | |
| 
 | |
| #include <stdio.h> // required for jpeglib.h
 | |
| extern "C"
 | |
| {
 | |
| 	#include <jpeglib.h>
 | |
| 	#include <jerror.h>
 | |
| }
 | |
| 
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace video
 | |
| {
 | |
| 
 | |
| // The writer uses a 4k buffer and flushes to disk each time it's filled
 | |
| #define OUTPUT_BUF_SIZE 4096
 | |
| typedef struct
 | |
| {
 | |
| 	struct jpeg_destination_mgr pub;/* public fields */
 | |
| 
 | |
| 	io::IWriteFile* file;		/* target file */
 | |
| 	JOCTET buffer[OUTPUT_BUF_SIZE];	/* image buffer */
 | |
| } mem_destination_mgr;
 | |
| 
 | |
| 
 | |
| typedef mem_destination_mgr * mem_dest_ptr;
 | |
| 
 | |
| 
 | |
| // init
 | |
| static void jpeg_init_destination(j_compress_ptr cinfo)
 | |
| {
 | |
| 	mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
 | |
| 	dest->pub.next_output_byte = dest->buffer;
 | |
| 	dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
 | |
| }
 | |
| 
 | |
| 
 | |
| // flush to disk and reset buffer
 | |
| static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
 | |
| {
 | |
| 	mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
 | |
| 
 | |
| 	// for now just exit upon file error
 | |
| 	if (dest->file->write(dest->buffer, OUTPUT_BUF_SIZE) != OUTPUT_BUF_SIZE)
 | |
| 		ERREXIT (cinfo, JERR_FILE_WRITE);
 | |
| 
 | |
| 	dest->pub.next_output_byte = dest->buffer;
 | |
| 	dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void jpeg_term_destination(j_compress_ptr cinfo)
 | |
| {
 | |
| 	mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
 | |
| 	const size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
 | |
| 	// for now just exit upon file error
 | |
| 	if (dest->file->write(dest->buffer, datacount) != datacount)
 | |
| 		ERREXIT (cinfo, JERR_FILE_WRITE);
 | |
| }
 | |
| 
 | |
| 
 | |
| // set up buffer data
 | |
| static void jpeg_file_dest(j_compress_ptr cinfo, io::IWriteFile* file)
 | |
| {
 | |
| 	if (cinfo->dest == NULL)
 | |
| 	{ /* first time for this JPEG object? */
 | |
| 		cinfo->dest = (struct jpeg_destination_mgr *)
 | |
| 			(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
 | |
| 						JPOOL_PERMANENT,
 | |
| 						sizeof(mem_destination_mgr));
 | |
| 	}
 | |
| 
 | |
| 	mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;  /* for casting */
 | |
| 
 | |
| 	/* Initialize method pointers */
 | |
| 	dest->pub.init_destination = jpeg_init_destination;
 | |
| 	dest->pub.empty_output_buffer = jpeg_empty_output_buffer;
 | |
| 	dest->pub.term_destination = jpeg_term_destination;
 | |
| 
 | |
| 	/* Initialize private member */
 | |
| 	dest->file = file;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* write_JPEG_memory: store JPEG compressed image into memory.
 | |
| */
 | |
| static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality)
 | |
| {
 | |
| 	void (*format)(const void*, s32, void*) = 0;
 | |
| 	switch( image->getColorFormat () )
 | |
| 	{
 | |
| 		case ECF_R8G8B8:
 | |
| 			format = CColorConverter::convert_R8G8B8toR8G8B8;
 | |
| 			break;
 | |
| 		case ECF_A8R8G8B8:
 | |
| 			format = CColorConverter::convert_A8R8G8B8toR8G8B8;
 | |
| 			break;
 | |
| 		case ECF_A1R5G5B5:
 | |
| 			format = CColorConverter::convert_A1R5G5B5toB8G8R8;
 | |
| 			break;
 | |
| 		case ECF_R5G6B5:
 | |
| 			format = CColorConverter::convert_R5G6B5toR8G8B8;
 | |
| 			break;
 | |
| 		default:
 | |
| 			os::Printer::log("writeJPEGFile does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING);
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	// couldn't find a color converter
 | |
| 	if ( 0 == format )
 | |
| 		return false;
 | |
| 
 | |
| 	const core::dimension2du dim = image->getDimension();
 | |
| 
 | |
| 	struct jpeg_compress_struct cinfo;
 | |
| 	struct jpeg_error_mgr jerr;
 | |
| 	cinfo.err = jpeg_std_error(&jerr);
 | |
| 
 | |
| 	jpeg_create_compress(&cinfo);
 | |
| 	jpeg_file_dest(&cinfo, file);
 | |
| 	cinfo.image_width = dim.Width;
 | |
| 	cinfo.image_height = dim.Height;
 | |
| 	cinfo.input_components = 3;
 | |
| 	cinfo.in_color_space = JCS_RGB;
 | |
| 
 | |
| 	jpeg_set_defaults(&cinfo);
 | |
| 
 | |
| 	if ( 0 == quality )
 | |
| 		quality = 75;
 | |
| 
 | |
| 	jpeg_set_quality(&cinfo, quality, TRUE);
 | |
| 	jpeg_start_compress(&cinfo, TRUE);
 | |
| 
 | |
| 	u8 * dest = new u8[dim.Width*3];
 | |
| 
 | |
| 	if (dest)
 | |
| 	{
 | |
| 		const u32 pitch = image->getPitch();
 | |
| 		JSAMPROW row_pointer[1];      /* pointer to JSAMPLE row[s] */
 | |
| 		row_pointer[0] = dest;
 | |
| 
 | |
| 		u8* src = (u8*)image->getData();
 | |
| 
 | |
| 		while (cinfo.next_scanline < cinfo.image_height)
 | |
| 		{
 | |
| 			// convert next line
 | |
| 			format( src, dim.Width, dest );
 | |
| 			src += pitch;
 | |
| 			jpeg_write_scanlines(&cinfo, row_pointer, 1);
 | |
| 		}
 | |
| 
 | |
| 		delete [] dest;
 | |
| 
 | |
| 		/* Step 6: Finish compression */
 | |
| 		jpeg_finish_compress(&cinfo);
 | |
| 	}
 | |
| 
 | |
| 	/* Step 7: Destroy */
 | |
| 	jpeg_destroy_compress(&cinfo);
 | |
| 
 | |
| 	return (dest != 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| } // namespace video
 | |
| } // namespace irr
 | |
| 
 | |
| 
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace video
 | |
| {
 | |
| 
 | |
| IImageWriter* createImageWriterJPG()
 | |
| {
 | |
| 	return new CImageWriterJPG;
 | |
| }
 | |
| 
 | |
| CImageWriterJPG::CImageWriterJPG()
 | |
| {
 | |
| #ifdef _DEBUG
 | |
| 	setDebugName("CImageWriterJPG");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CImageWriterJPG::isAWriteableFileExtension(const io::path& filename) const
 | |
| {
 | |
| 	return core::hasFileExtension ( filename, "jpg", "jpeg" );
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CImageWriterJPG::writeImage(io::IWriteFile *file, IImage *image, u32 quality) const
 | |
| {
 | |
| 	return writeJPEGFile(file, image, quality);
 | |
| }
 | |
| 
 | |
| } // namespace video
 | |
| } // namespace irr
 |