summaryrefslogtreecommitdiff
path: root/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
blob: 4104527f83f00c6bd0bafc12b9cacd0841ac9b73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/** 
 * @file llimage_libtest.cpp
 * @author Merov Linden
 * @brief Integration test for the llimage library
 *
 * $LicenseInfo:firstyear=2011&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2011, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */
#include "linden_common.h"
#include "llpointer.h"

#include "llimage_libtest.h"

// Linden library includes
#include "llimage.h"
#include "llimagejpeg.h"
#include "llimagepng.h"
#include "llimagebmp.h"
#include "llimagetga.h"
#include "llimagej2c.h"
#include "lldir.h"

// system libraries
#include <iostream>

// doc string provided when invoking the program with --help 
static const char USAGE[] = "\n"
"usage:\tllimage_libtest [options]\n"
"\n"
" --help                           print this help\n"
" --in <file1 .. file2>            list of image files to load and convert, patterns can be used\n"
" --out <file1 .. file2> OR <type> list of image files to create (assumes same order as --in files)\n"
"                                  OR 3 letters file type extension to convert each input file into\n"
"\n";

// Create an empty formatted image instance of the correct type from the filename
LLPointer<LLImageFormatted> create_image(const std::string &filename)
{
	std::string exten = gDirUtilp->getExtension(filename);
	U32 codec = LLImageBase::getCodecFromExtension(exten);
	
	LLPointer<LLImageFormatted> image;
	switch (codec)
	{
		case IMG_CODEC_BMP:
			image = new LLImageBMP();
			break;
		case IMG_CODEC_TGA:
			image = new LLImageTGA();
			break;
		case IMG_CODEC_JPEG:
			image = new LLImageJPEG();
			break;
		case IMG_CODEC_J2C:
			image = new LLImageJ2C();
			break;
		case IMG_CODEC_PNG:
			image = new LLImagePNG();
			break;
		default:
			return NULL;
	}
	
	return image;
}

// Load an image from file and return a raw (decompressed) instance of its data
LLPointer<LLImageRaw> load_image(const std::string &src_filename)
{
	LLPointer<LLImageFormatted> image = create_image(src_filename);

	if (!image->load(src_filename))
	{
		return NULL;
	}
	
	if(	(image->getComponents() != 3) && (image->getComponents() != 4) )
	{
		std::cout << "Image files with less than 3 or more than 4 components are not supported\n";
		return NULL;
	}
	
	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
	if (!image->decode(raw_image, 0.0f))
	{
		return NULL;
	}
	
	return raw_image;
}

// Save a raw image instance into a file
bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image)
{
	LLPointer<LLImageFormatted> image = create_image(dest_filename);
	
	if (!image->encode(raw_image, 0.0f))
	{
		return false;
	}
	
	return image->save(dest_filename);
}

void store_input_file(std::list<std::string> &input_filenames, const std::string &path)
{
	// Break the incoming path in its components
	std::string dir = gDirUtilp->getDirName(path);
	std::string name = gDirUtilp->getBaseFileName(path);
	std::string exten = gDirUtilp->getExtension(path);

	// std::cout << "store_input_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
	
	// If extension is not an image type or "*", exit
	// Note: we don't support complex patterns for the extension like "j??"
	// Note: on most shells, the pattern expansion is done by the shell so that pattern matching limitation is actually not a problem
	if ((exten.compare("*") != 0) && (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID))
	{
		return;
	}

	if ((name.find('*') != -1) || ((name.find('?') != -1)))
	{
		// If file name is a pattern, iterate to get each file name and store
		std::string next_name;
		while (gDirUtilp->getNextFileInDir(dir,name,next_name))
		{
			std::string file_name = dir + gDirUtilp->getDirDelimiter() + next_name;
			input_filenames.push_back(file_name);
		}
	}
	else
	{
		// Verify that the file does exist before storing 
		if (gDirUtilp->fileExists(path))
		{
			input_filenames.push_back(path);
		}
		else
		{
			std::cout << "store_input_file : the file " << path << " could not be found" << std::endl;
		}
	}	
}

void store_output_file(std::list<std::string> &output_filenames, std::list<std::string> &input_filenames, const std::string &path)
{
	// Break the incoming path in its components
	std::string dir = gDirUtilp->getDirName(path);
	std::string name = gDirUtilp->getBaseFileName(path);
	std::string exten = gDirUtilp->getExtension(path);
	
	// std::cout << "store_output_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
	
	if (dir.empty() && exten.empty())
	{
		// If dir and exten are empty, we interpret the name as a file extension type name and will iterate through input list to populate the output list
		exten = name;
		// Make sure the extension is an image type
		if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
		{
			return;
		}
		std::string delim = gDirUtilp->getDirDelimiter();
		std::list<std::string>::iterator in_file  = input_filenames.begin();
		std::list<std::string>::iterator end = input_filenames.end();
		for (; in_file != end; ++in_file)
		{
			dir = gDirUtilp->getDirName(*in_file);
			name = gDirUtilp->getBaseFileName(*in_file,true);
			std::string file_name = dir + delim + name + "." + exten;
			output_filenames.push_back(file_name);
		}
	}
	else
	{
		// Make sure the extension is an image type
		if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
		{
			return;
		}
		// Store the path
		output_filenames.push_back(path);
	}
}

int main(int argc, char** argv)
{
	// List of input and output files
	std::list<std::string> input_filenames;
	std::list<std::string> output_filenames;

	// Init whatever is necessary
	ll_init_apr();
	LLImage::initClass();

	// Analyze command line arguments
	for (int arg = 1; arg < argc; ++arg)
	{
		if (!strcmp(argv[arg], "--help"))
		{
            // Send the usage to standard out
            std::cout << USAGE << std::endl;
			return 0;
		}
		else if (!strcmp(argv[arg], "--in") && arg < argc-1)
		{
			std::string file_name = argv[arg+1];
			while (file_name[0] != '-')		// if arg starts with '-', we consider it's not a file name but some other argument
			{
				// std::cout << "input file name : " << file_name << std::endl;				
				store_input_file(input_filenames, file_name);
				arg += 1;					// Skip that arg now we know it's a file name
				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
					break;
				file_name = argv[arg+1];	// Next argument and loop over
			}
		}
		else if (!strcmp(argv[arg], "--out") && arg < argc-1)
		{
			std::string file_name = argv[arg+1];
			while (file_name[0] != '-')		// if arg starts with '-', we consider it's not a file name but some other argument
			{
				// std::cout << "output file name : " << file_name << std::endl;				
				store_output_file(output_filenames, input_filenames, file_name);
				arg += 1;					// Skip that arg now we know it's a file name
				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list
					break;
				file_name = argv[arg+1];	// Next argument and loop over
			}
		}		
	}
		
	// Analyze the list of (input,output) files
	if (input_filenames.size() == 0)
	{
		std::cout << "No input file, nothing to do -> exit" << std::endl;
		return 0;
	}

	// Perform action on each input file
	std::list<std::string>::iterator in_file  = input_filenames.begin();
	std::list<std::string>::iterator out_file = output_filenames.begin();
	std::list<std::string>::iterator in_end = input_filenames.end();
	std::list<std::string>::iterator out_end = output_filenames.end();
	for (; in_file != in_end; ++in_file)
	{
		// Load file
		LLPointer<LLImageRaw> raw_image = load_image(*in_file);
		if (!raw_image)
		{
			std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
			continue;
		}
	
		// Save file
		if (out_file != out_end)
		{
			if (!save_image(*out_file, raw_image))
			{
				std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;
			}
			else
			{
				std::cout << *in_file << " -> " << *out_file << std::endl;
			}
			++out_file;
		}

		// Output stats on each file
	}
	
	// Output perf data if required by user
	
	// Cleanup and exit
	LLImage::cleanupClass();
	
	return 0;
}