Пример #1
0
void cutter::load_masks(const config& conf)
{
	const config::child_list& masks = conf.get_children("mask");

	for(config::child_list::const_iterator itor = masks.begin();
		       itor != masks.end(); ++itor) {

		const std::string name = (**itor)["name"];
		const std::string image = get_mask_dir() + "/" + (**itor)["image"];

		if(verbose_) {
			std::cerr << "Adding mask " << name << "\n";
		}

		if(image.empty())
			throw exploder_failure("Missing image for mask " + name);

		const exploder_point shift((**itor)["shift"]);
		const exploder_rect cut((**itor)["cut"]);

		if(masks_.find(name) != masks_.end() && masks_[name].filename != image) {
			throw exploder_failure("Mask " + name +
					" correspond to two different files: " +
					name + " and " +
					masks_.find(name)->second.filename);
		}

		if(masks_.find(name) == masks_.end()) {
			mask& cur_mask = masks_[name];

			cur_mask.name = name;
			cur_mask.shift = shift;
			cur_mask.cut = cut;
			cur_mask.filename = image;
			surface tmp(IMG_Load(image.c_str()));
			if(tmp == NULL)
				throw exploder_failure("Unable to load mask image " + image);

			cur_mask.image = surface(make_neutral_surface(tmp));
		}

		if(masks_[name].image == NULL)
			throw exploder_failure("Unable to load mask image " + image);
	}
}
void cutter::load_masks(const config& conf)
{
	BOOST_FOREACH(const config &m, conf.child_range("mask"))
	{
		const std::string name = m["name"];
		const std::string image = get_mask_dir() + "/" + std::string(m["image"]);

		if(verbose_) {
			std::cerr << "Adding mask " << name << "\n";
		}

		if(image.empty())
			throw exploder_failure("Missing image for mask " + name);

		const exploder_point shift(m["shift"]);
		const exploder_rect cut(m["cut"]);

		if(masks_.find(name) != masks_.end() && masks_[name].filename != image) {
			throw exploder_failure("Mask " + name +
					" correspond to two different files: " +
					name + " and " +
					masks_.find(name)->second.filename);
		}

		if(masks_.find(name) == masks_.end()) {
			mask& cur_mask = masks_[name];

			cur_mask.name = name;
			cur_mask.shift = shift;
			cur_mask.cut = cut;
			cur_mask.filename = image;
			surface tmp(IMG_Load(image.c_str()));
			if(tmp == NULL)
				throw exploder_failure("Unable to load mask image " + image);

			cur_mask.image = surface(make_neutral_surface(tmp));
		}

		if(masks_[name].image == NULL)
			throw exploder_failure("Unable to load mask image " + image);
	}
}
void cutter::add_sub_image(const surface &surf, surface_map &map, const config* config)
{
	const std::string name = (*config)["name"];
	if(name.empty())
		throw exploder_failure("Un-named sub-image");

	if(masks_.find(name) == masks_.end())
		throw exploder_failure("Unable to find mask corresponding to " + name);

	const cutter::mask& mask = masks_[name];

	std::vector<std::string> pos = utils::split((*config)["pos"]);
	if(pos.size() != 2)
		throw exploder_failure("Invalid position " + (*config)["pos"].str());

	int x = atoi(pos[0].c_str());
	int y = atoi(pos[1].c_str());

	const SDL_Rect cut = create_rect(x - mask.shift.x
			, y - mask.shift.y
			, mask.image->w
			, mask.image->h);

	typedef std::pair<std::string, positioned_surface> sme;

	positioned_surface ps;
	ps.image = surface(::cut_surface(surf, cut));
	if(ps.image == NULL)
		throw exploder_failure("Unable to cut surface!");
	ps.name = name;
	ps.mask = mask;
	ps.pos.x = x - mask.shift.x;
	ps.pos.y = y - mask.shift.y;
	map.insert(sme(name, ps));

	if(verbose_) {
		std::cerr << "Extracting sub-image " << name << ", position (" << x << ", " << y << ")\n";
	}
}
const config cutter::load_config(const std::string &filename)
{
	const std::string conf_string = find_configuration(filename);

	config res;

	try {
		scoped_istream stream = preprocess_file(conf_string);
		read(res, *stream);
	} catch(config::error& err) {
		throw exploder_failure("Unable to load the configuration for the file " + filename + ": "+ err.message);
	}

	return res;
}
//saves the given SDL structure into a given filename.
void save_image(surface surf, const std::string &filename)
{
	//opens the actual file
	const util::scoped_FILE file(fopen(filename.c_str(),"wb"));

	//initializes PNG write structures
	//TODO: review whether providing NULL error handlers is something
	//sensible
	png_struct* png_ptr = png_create_write_struct
		(PNG_LIBPNG_VER_STRING, reinterpret_cast<png_voidp>(png_voidp_NULL),
		 png_error_ptr_NULL, png_error_ptr_NULL);
	if(!png_ptr)
		throw exploder_failure("Unable to initialize the png write structure");

	png_info* info_ptr = png_create_info_struct(png_ptr);
	if(!info_ptr) {
		png_destroy_write_struct(&png_ptr,
				static_cast<png_infopp>(NULL));
		throw exploder_failure("Unable to initialize the png info structure");
	}

	//instructs the PNG library to use the open file
	png_init_io(png_ptr, file);

	//sets compression level to the maximum
	png_set_compression_level(png_ptr,
			Z_BEST_COMPRESSION);

	//configures the header
	png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h,
			8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	//puts the actual image data in the row_pointers array
	png_byte **row_pointers = new png_byte *[surf->h];
	surface_lock lock(surf);

	//converts the data to the RGBA format. We cannot pass SDL data
	//directly to the png lib, even if we know its pixel format, because of
	//endianness problems.
	util::scoped_array<rgba> rgba_data(new rgba[surf->w * surf->h]);

	Uint32 *surf_data = lock.pixels();
	int pos = 0;
	for(int y = 0; y < surf->h; ++y) {
		row_pointers[y] = reinterpret_cast<png_byte*>(rgba_data + pos);
		for(int x = 0; x < surf->w; ++x) {
			Uint8 red, green, blue, alpha;
			SDL_GetRGBA(*surf_data, surf->format, &red, &green, &blue, &alpha);
			rgba_data[pos].r = red;
			rgba_data[pos].g = green;
			rgba_data[pos].b = blue;
			rgba_data[pos].a = alpha;
			pos++;
			surf_data++;
		}
	}
	png_set_rows(png_ptr, info_ptr, row_pointers);

	//writes the actual image data
	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

	//cleans everything
	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);
	delete [] row_pointers;
}
surface composer::compose(const std::string &src, const std::string &dest)
{
	cutter cut;
	cut.set_verbose(verbose_);

	const config src_conf = cut.load_config(src);
	const config dest_conf = cut.load_config(dest);

	if(verbose_) {
		std::cerr << "Loading masks...\n";
	}
	cut.load_masks(src_conf);
	cut.load_masks(dest_conf);

	if(verbose_) {
		std::cerr << "Loading images...\n";
	}
	const surface src_surface(make_neutral_surface(IMG_Load(src.c_str())));
	if(src_surface == NULL)
		throw exploder_failure("Unable to load the source image " + src);

	const surface dest_surface(make_neutral_surface(IMG_Load(dest.c_str())));
	if(dest_surface == NULL)
		throw exploder_failure("Unable to load the destination image " + dest);

	if(verbose_) {
		std::cerr << "Cutting images...\n";
	}
	const cutter::surface_map src_surfaces = cut.cut_surface(src_surface, src_conf);
	const cutter::surface_map dest_surfaces = cut.cut_surface(dest_surface, dest_conf);

	for(cutter::surface_map::const_iterator itor = dest_surfaces.begin();
			itor != dest_surfaces.end(); ++itor) {

		const std::string& name = itor->second.name;

		if(src_surfaces.find(name) == src_surfaces.end())
			continue;

		const cutter::positioned_surface& src_ps = src_surfaces.find(name)->second;
		const cutter::positioned_surface& dest_ps = itor->second;

		if(!image_empty(dest_ps.image)) {
			if(interactive_) {
				//TODO: make "interactive" mode work
			} else {
				std::cerr << "Warning: element " << name << " not empty on destination image\n";
			}
		}
		if(verbose_) {
			std::cerr << "Inserting image " << name
				<< " on position (" << dest_ps.pos.x
				<< ", " << dest_ps.pos.y << ")\n";
		}
		masked_overwrite_surface(dest_surface, src_ps.image,
				src_ps.mask.image,
				dest_ps.pos.x, dest_ps.pos.y);
	}

	return dest_surface;
}
Пример #7
0
int main(int argc, char* argv[])
{
	std::string src;
	std::string dest_dir;
	cutter cut;

	// Parse arguments that shouldn't require a display device
	int arg;
	for(arg = 1; arg != argc; ++arg) {
		const std::string val(argv[arg]);
		if(val.empty()) {
			continue;
		}

		if(val == "--help" || val == "-h") {
			print_usage(argv[0]);
			return 0;
		} else if(val == "--verbose" || val == "-v") {
			cut.set_verbose(true);
		} else if(val == "--directory" || val == "-d" ) {
			game_config::path = argv[++arg];
		} else {
			if(src.empty()) {
				src = val;
			} else if(dest_dir.empty()) {
				dest_dir = val;
			} else {
				print_usage(argv[0]);
				return 1;
			}
		}
	}

	if(src.empty() || dest_dir.empty()) {
		print_usage(argv[0]);
		return 1;
	}

	try {
		const config conf = cut.load_config(src);
		cut.load_masks(conf);

		const surface src_surface(make_neutral_surface(IMG_Load(src.c_str())));
		if(src_surface == NULL)
			throw exploder_failure("Unable to load the source image " + src);

		const cutter::surface_map surfaces = cut.cut_surface(src_surface, conf);

		for(cutter::surface_map::const_iterator itor = surfaces.begin();
				itor != surfaces.end(); ++itor) {
			const cutter::mask &mask = itor->second.mask;

			surface surf = create_compatible_surface(
					  itor->second.image
					, mask.cut.w
					, mask.cut.h);

			masked_overwrite_surface(surf, itor->second.image, mask.image,
					mask.cut.x - mask.shift.x, mask.cut.y - mask.shift.y);

			save_image(surf, dest_dir + "/" + mask.name + ".png");
		}

	} catch(exploder_failure& err) {
		std::cerr << "Failed: " << err.message << "\n";
		return 1;
	}

	return 0;
}