PageRenderTime 24ms CodeModel.GetById 2ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llimage/llimagedimensionsinfo.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 222 lines | 142 code | 37 blank | 43 comment | 21 complexity | 119f87edfde8f0cd862bd2c7cff05b39 MD5 | raw file
  1/** 
  2 * @file llimagedimensionsinfo.cpp
  3 *
  4 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  5 * Second Life Viewer Source Code
  6 * Copyright (C) 2010, Linden Research, Inc.
  7 * 
  8 * This library is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU Lesser General Public
 10 * License as published by the Free Software Foundation;
 11 * version 2.1 of the License only.
 12 * 
 13 * This library is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 16 * Lesser General Public License for more details.
 17 * 
 18 * You should have received a copy of the GNU Lesser General Public
 19 * License along with this library; if not, write to the Free Software
 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 21 * 
 22 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 23 * $/LicenseInfo$
 24 */
 25
 26#include "linden_common.h"
 27#include "stdtypes.h"
 28
 29#include "llimagejpeg.h"
 30
 31#include "llimagedimensionsinfo.h"
 32
 33// Value is true if one of Libjpeg's functions has encountered an error while working.
 34static bool sJpegErrorEncountered = false;
 35
 36bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
 37{
 38	clean();
 39
 40	mSrcFilename = src_filename;
 41
 42	S32 file_size = 0;
 43	apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size);
 44
 45	if (s != APR_SUCCESS)
 46	{
 47		setLastError("Unable to open file for reading", src_filename);
 48		return false;
 49	}
 50
 51	if (file_size == 0)
 52	{
 53		setLastError("File is empty",src_filename);
 54		return false;
 55	}
 56
 57	switch (codec)
 58	{
 59	case IMG_CODEC_BMP:
 60		return getImageDimensionsBmp();
 61	case IMG_CODEC_TGA:
 62		return getImageDimensionsTga();
 63	case IMG_CODEC_JPEG:
 64		return getImageDimensionsJpeg();
 65	case IMG_CODEC_PNG:
 66		return getImageDimensionsPng();
 67	default:
 68		return false;
 69
 70	}
 71}
 72
 73
 74bool LLImageDimensionsInfo::getImageDimensionsBmp()
 75{
 76	// Make sure the file is long enough.
 77	const S32 DATA_LEN = 26; // BMP header (14) + DIB header size (4) + width (4) + height (4)
 78	if (!checkFileLength(DATA_LEN))
 79	{
 80		llwarns << "Premature end of file" << llendl;
 81		return false;
 82	}
 83
 84	// Read BMP signature.
 85	U8 signature[2];
 86	mInfile.read((void*)signature, sizeof(signature)/sizeof(signature[0]));
 87
 88	// Make sure this is actually a BMP file.
 89	// We only support Windows bitmaps (BM), according to LLImageBMP::updateData().
 90	if (signature[0] != 'B' || signature[1] != 'M')
 91	{
 92		llwarns << "Not a BMP" << llendl;
 93		return false;
 94	}
 95
 96	// Read image dimensions.
 97	mInfile.seek(APR_CUR, 16);
 98	mWidth = read_reverse_s32();
 99	mHeight = read_reverse_s32();
100
101	return true;
102}
103
104bool LLImageDimensionsInfo::getImageDimensionsTga()
105{
106	const S32 TGA_FILE_HEADER_SIZE = 12;
107
108	// Make sure the file is long enough.
109	if (!checkFileLength(TGA_FILE_HEADER_SIZE + 1 /* width */ + 1 /* height */))
110	{
111		llwarns << "Premature end of file" << llendl;
112		return false;
113	}
114
115	// *TODO: Detect non-TGA files somehow.
116	mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE);
117	mWidth = read_byte() | read_byte() << 8;
118	mHeight = read_byte() | read_byte() << 8;
119
120	return true;
121}
122
123bool LLImageDimensionsInfo::getImageDimensionsPng()
124{
125	const S32 PNG_MAGIC_SIZE = 8;
126
127	// Make sure the file is long enough.
128	if (!checkFileLength(PNG_MAGIC_SIZE + 8 + sizeof(S32) * 2 /* width, height */))
129	{
130		llwarns << "Premature end of file" << llendl;
131		return false;
132	}
133
134	// Read PNG signature.
135	const U8 png_magic[PNG_MAGIC_SIZE] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
136	U8 signature[PNG_MAGIC_SIZE];
137	mInfile.read((void*)signature, PNG_MAGIC_SIZE);
138
139	// Make sure it's a PNG file.
140	if (memcmp(signature, png_magic, PNG_MAGIC_SIZE) != 0)
141	{
142		llwarns << "Not a PNG" << llendl;
143		return false;
144	}
145
146	// Read image dimensions.
147	mInfile.seek(APR_CUR, 8 /* chunk length + chunk type */);
148	mWidth = read_s32();
149	mHeight = read_s32();
150
151	return true;
152}
153
154// Called instead of exit() if Libjpeg encounters an error.
155void on_jpeg_error(j_common_ptr cinfo)
156{
157	(void) cinfo;
158	sJpegErrorEncountered = true;
159	llwarns << "Libjpeg has encountered an error!" << llendl;
160}
161
162bool LLImageDimensionsInfo::getImageDimensionsJpeg()
163{
164	sJpegErrorEncountered = false;
165	clean();
166	FILE *fp = fopen (mSrcFilename.c_str(), "rb");
167	if (fp == NULL) 
168	{
169		setLastError("Unable to open file for reading", mSrcFilename);
170		return false;
171	}
172
173	/* Make sure this is a JPEG file. */
174	const size_t JPEG_MAGIC_SIZE = 2;
175	const uint8_t jpeg_magic[JPEG_MAGIC_SIZE] = {0xFF, 0xD8};
176	uint8_t signature[JPEG_MAGIC_SIZE];
177
178	if (fread(signature, sizeof(signature), 1, fp) != 1)
179	{
180		llwarns << "Premature end of file" << llendl;
181		return false;
182	}
183	if (memcmp(signature, jpeg_magic, JPEG_MAGIC_SIZE) != 0)
184	{
185		llwarns << "Not a JPEG" << llendl;
186		return false;
187	}
188	fseek(fp, 0, SEEK_SET); // go back to start of the file
189
190	/* Init jpeg */
191	jpeg_error_mgr jerr;
192	jpeg_decompress_struct cinfo;
193	cinfo.err = jpeg_std_error(&jerr);
194	// Call our function instead of exit() if Libjpeg encounters an error.
195	// This is done to avoid crash in this case (STORM-472).
196	cinfo.err->error_exit = on_jpeg_error;
197
198	jpeg_create_decompress	(&cinfo);
199	jpeg_stdio_src		(&cinfo, fp);
200	jpeg_read_header	(&cinfo, TRUE);
201	cinfo.out_color_space = JCS_RGB;
202	jpeg_start_decompress	(&cinfo);
203
204	mHeight = cinfo.output_width;
205	mHeight = cinfo.output_height;
206
207	jpeg_destroy_decompress(&cinfo);
208	fclose(fp);
209
210	return !sJpegErrorEncountered;
211}
212
213bool LLImageDimensionsInfo::checkFileLength(S32 min_len)
214{
215	// Make sure the file is not shorter than min_len bytes.
216	// so that we don't have to check value returned by each read() or seek().
217	char* buf = new char[min_len];
218	int nread = mInfile.read(buf, min_len);
219	delete[] buf;
220	mInfile.seek(APR_SET, 0);
221	return nread == min_len;
222}