⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 image_filters.cpp

📁 一个开源的Flash 播放器,可以在Windows/Linux 上运行
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// image_filters.cpp	-- Original code by Dale Schumacher, public domain 1991

// See _Graphics Gems III_ "General Filtered Image Rescaling", Dale A. Schumacher

// Modifications by Thatcher Ulrich <tu@tulrich.com> 2002

// This source code has been donated to the Public Domain.  Do
// whatever you want with it.

// A series of image rescaling functions.  tulrich: Mostly I just
// converted from K&R C to C-like C++, changed the interfaces a bit,
// etc.


#include "base/image.h"
#include "base/utility.h"
#include "base/container.h"
#include "base/tu_math.h"
#include <stdio.h>
#include <string.h>


namespace {
// anonymous namespace to hold local stuff.


inline void* my_calloc(int count, int size)
{
	void*	mem = (void*) new char[count * size];
	memset(mem, 0, count * size);
	return mem;
}


inline void	my_cfree(void* mem)
{
	delete [] (char*) mem;
}


void	get_row(Uint8* row, image::rgb* image, int x0, int xsize, int y)
// Copy RGB data from the specified row into the given buffer.
{
	y = iclamp(y, 0, image->m_height - 1);
	int	x1 = x0 + xsize - 1;
	if (x1 >= image->m_width) {
		// clip, then extend.
		int	extra_pixels = x1 - image->m_width + 1;
		Uint8*	p = ((Uint8*) image->m_data) + (y * image->m_pitch);
		memcpy(row, p + x0 * 3, (3 * (image->m_width - x0)));
		// repeat last pixel
		p = p + (image->m_width - 1) * 3;
		Uint8*	q = row + (image->m_width - x0) * 3;
		while (extra_pixels > 0) {
			*(q + 0) = *(p + 0);
			*(q + 1) = *(p + 1);
			*(q + 2) = *(p + 2);
			q += 3;
			extra_pixels--;
		}
	}
	else
	{
		memcpy(row, ((Uint8*) image->m_data) + (y * image->m_pitch) + x0 * 3, (3 * xsize));
	}
}


void	get_row(Uint8* row, image::rgba* image, int x0, int xsize, int y)
// Copy RGBA data from the specified row into the given buffer.
{
	y = iclamp(y, 0, image->m_height - 1);
	int	x1 = x0 + xsize - 1;
	if (x1 >= image->m_width) {
		// clip, then extend.
		int	extra_pixels = x1 - image->m_width + 1;
		Uint8*	p = ((Uint8*) image->m_data) + (y * image->m_pitch);
		memcpy(row, p + x0 * 4, (4 * (image->m_width - x0)));
		// repeat last pixel
		p = p + (image->m_width - 1) * 4;
		Uint8*	q = row + (image->m_width - x0) * 4;
		while (extra_pixels > 0) {
			*(q + 0) = *(p + 0);
			*(q + 1) = *(p + 1);
			*(q + 2) = *(p + 2);
			*(q + 3) = *(p + 3);
			q += 4;
			extra_pixels--;
		}
	}
	else
	{
		memcpy(row, ((Uint8*) image->m_data) + (y * image->m_pitch) + x0 * 4, (4 * xsize));
	}
}


void	get_column(Uint8* column, image::rgb* image, int x)
// Copy RGB data from the specified column into the given buffer.
{
	int	i, d;
	Uint8*	p;

	if ((x < 0) || (x >= image->m_width)) {
		assert(0);
		x = iclamp(x, 0, image->m_width - 1);
	}

	d = image->m_pitch;
	for (i = image->m_height, p = ((Uint8*) image->m_data) + x * 3; i-- > 0; p += d) {
		*column++ = *p;
		*column++ = *(p + 1);
		*column++ = *(p + 2);
	}
}


void	get_column(Uint8* column, image::rgba* image, int x)
// Copy RGBA data from the specified column into the given buffer.
{
	int	i, d;
	Uint8*	p;

	if ((x < 0) || (x >= image->m_width)) {
		assert(0);
		x = iclamp(x, 0, image->m_width - 1);
	}

	d = image->m_pitch;
	for (i = image->m_height, p = ((Uint8*) image->m_data) + x * 4; i-- > 0; p += d) {
		*column++ = *p;
		*column++ = *(p + 1);
		*column++ = *(p + 2);
		*column++ = *(p + 3);
	}
}


void	put_pixel(image::rgb* image, int x, int y, float r, float g, float b)
// Clamp {r, g, b} to [0,255], and write pixel data to the given image
// at (x, y).
{
	static image::rgb*	im = NULL;
	static int	yy = -1;
	static Uint8*	p = NULL;

	if ((x < 0) || (x >= image->m_width) || (y < 0) || (y >= image->m_height)) {
		assert(0);
		return;
	}
	if ((im != image) || (yy != y)) {
		im = image;
		yy = y;
		p = ((Uint8*) image->m_data) + (y * image->m_pitch);
	}
	p[x * 3 + 0] = iclamp(frnd(r), 0, 255);
	p[x * 3 + 1] = iclamp(frnd(g), 0, 255);
	p[x * 3 + 2] = iclamp(frnd(b), 0, 255);
}


void	put_pixel(image::rgba* image, int x, int y, float r, float g, float b, float a)
// Clamp {r, g, b, a} to [0,255], and write pixel data to the given image
// at (x, y).
{
	static image::rgba*	im = NULL;
	static int	yy = -1;
	static Uint8*	p = NULL;

	if ((x < 0) || (x >= image->m_width) || (y < 0) || (y >= image->m_height)) {
		assert(0);
		return;
	}
	if ((im != image) || (yy != y)) {
		im = image;
		yy = y;
		p = ((Uint8*) image->m_data) + (y * image->m_pitch);
	}
	p[x * 4	+ 0] = iclamp(frnd(r), 0, 255);
	p[x * 4	+ 1] = iclamp(frnd(g), 0, 255);
	p[x * 4	+ 2] = iclamp(frnd(b), 0, 255);
	p[x * 4	+ 3] = iclamp(frnd(a), 0, 255);
}


/*
 *	filter function definitions
 */


// SOME_CUBIC

#define	cubic_filter_support		(1.0f)

float	cubic_filter(float t)
// Cubix approximation to the central hump of Sinc.
{
	/* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
	if(t < 0.0f) t = -t;
	if(t < 1.0f) return((2.0f * t - 3.0f) * t * t + 1.0f);
	return(0.0f);
}


// BOX

#define	box_support		(0.5f)

float	box_filter(float t)
{
	if((t > -0.5) && (t <= 0.5)) return(1.0);
	return(0.0);
}


// TRIANGLE

#define	triangle_support	(1.0)

float	triangle_filter(float t)
{
	if(t < 0.0f) t = -t;
	if(t < 1.0f) return(1.0f - t);
	return(0.0f);
}


// BELL

#define	bell_support		(1.5)

float	bell_filter(float t)
/* box (*) box (*) box */
{
	if(t < 0) t = -t;
	if(t < 0.5f) return(0.75f - (t * t));
	if(t < 1.5f) {
		t = (t - 1.5f);
		return(0.5f * (t * t));
	}
	return(0.0f);
}


// B_SPLINE

#define	B_spline_support	(2.0f)

float	B_spline_filter(float t)
/* box (*) box (*) box (*) box */
{
	float	tt;

	if(t < 0.0f) t = -t;
	if(t < 1.0f) {
		tt = t * t;
		return((0.5f * tt * t) - tt + (2.0f / 3.0f));
	} else if (t < 2.0f) {
		t = 2.0f - t;
		return((1.0f / 6.0f) * (t * t * t));
	}
	return(0.0f);
}


// LANCZOS3

float	sinc(float x)
{
	x *= (float) M_PI;
	if (x != 0.0f) return(sinf(x) / x);
	return(1.0f);
}

#define	Lanczos3_support	(3.0f)

float	Lanczos3_filter(float t)
{
	if (t < 0.0f) t = -t;
	if (t < 3.0f) return(sinc(t) * sinc(t/3.0f));
	return(0.0f);
}


// MITCHELL

#define	Mitchell_support	(2.0f)

#define	B	(1.0f / 3.0f)
#define	C	(1.0f / 3.0f)

float	Mitchell_filter(float t)
{
	float tt;

	tt = t * t;
	if (t < 0.0f) t = -t;
	if (t < 1.0f) {
		t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
		   + ((-18.0f + 12.0f * B + 6.0f * C) * tt)
		   + (6.0f - 2.0f * B));
		return(t / 6.0f);
	} else if(t < 2.0f) {
		t = (((-1.0f * B - 6.0f * C) * (t * tt))
		   + ((6.0f * B + 30.0f * C) * tt)
		   + ((-12.0f * B - 48.0f * C) * t)
		   + (8.0f * B + 24 * C));
		return(t / 6.0f);
	}
	return(0.0f);
}


struct CONTRIB {
	int	pixel;
	float	weight;

	CONTRIB()
		: pixel(0), weight(0.f)
	{
	}

	CONTRIB(int p, float w)
		: pixel(p), weight(w)
	{
	}
};


};	// end anonymous namespace


namespace image {


enum filter_type {
	FILTER0 = 0,
	BOX = FILTER0,
	TRIANGLE,
	BELL,
	B_SPLINE,
	SOME_CUBIC,	// Cubic approximation of Sinc's hump (but no tails).
	LANCZOS3,
	MITCHELL,	// This one is alleged to be pretty nice.

	FILTER_COUNT
};

struct {
	float	(*filter_function)(float);
	float	support;
} filter_table[] =
{
	{ box_filter, box_support },
	{ triangle_filter, triangle_support },
	{ bell_filter, bell_support },
	{ B_spline_filter, B_spline_support },
	{ cubic_filter, cubic_filter_support },
	{ Lanczos3_filter, Lanczos3_support },
	{ Mitchell_filter, Mitchell_support },
};


// TODO: experiment with different filter functions.
filter_type	default_type = TRIANGLE;


void	resample(image::rgb* out, int out_x0, int out_y0, int out_x1, int out_y1,
		 image::rgb* in, float in_x0, float in_y0, float in_x1, float in_y1)
// Rescale the specified portion of the input image into the specified
// portion of the output image.  Coordinates are *inclusive*.
{
	assert(out_x0 <= out_x1);
	assert(out_y0 <= out_y1);
	assert(out_x0 >= 0 && out_x0 < out->m_width);
	assert(out_x1 >= 0 && out_x1 < out->m_width);
	assert(out_y0 >= 0 && out_y0 < out->m_height);
	assert(out_y1 >= 0 && out_y1 < out->m_height);

	float	(*filter_function)(float);
	float	support;

	// Pick a filter function & support.
	assert(default_type >= FILTER0 && default_type < FILTER_COUNT);
	filter_function = filter_table[default_type].filter_function;
	support = filter_table[default_type].support;


	image::rgb*	tmp;		/* intermediate image */
	float	xscale, yscale;		/* zoom scale factors */
	int i, j, k;			/* loop variables */
	int n;				/* pixel number */
	float center; int left, right;	/* filter calculation variables */
	float width, fscale, weight;	/* filter calculation variables */
	Uint8*	raster;			/* a row or column of pixels */

	array< array<CONTRIB> >	contrib;

	int	out_width = out_x1 - out_x0 + 1;
	int	out_height = out_y1 - out_y0 + 1;
	assert(out_width > 0);
	assert(out_height > 0);

	float	in_width = in_x1 - in_x0;
	float	in_height = in_y1 - in_y0;
	assert(in_width > 0);
	assert(in_height > 0);

	int	in_window_w = int(ceilf(in_x1) - floorf(in_x0) + 1);
	int	in_window_h = int(ceilf(in_y1) - floorf(in_y0) + 1);

	/* create intermediate image to hold horizontal zoom */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -