瀏覽代碼

If alpha is zero then sneakily replace it with a very small nonzero so that the color data is preserved.

Pre-process n1 so that we don't have to do it later on. Can't do n0 since it's used to find the coefficient index.
Jorge Rodriguez 11 年之前
父節點
當前提交
4b69c0637e
共有 2 個文件被更改,包括 65 次插入18 次删除
  1. 19 7
      stb_image_resize.h
  2. 46 11
      tests/resample_test.cpp

+ 19 - 7
stb_image_resize.h

@@ -795,12 +795,13 @@ static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, st
 
 
 static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
 static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
 {
 {
+	int num_contributors = stbir__get_horizontal_contributors(stbir_info);
 	int i;
 	int i;
 	for (i = 0; i < stbir_info->output_w; i++)
 	for (i = 0; i < stbir_info->output_w; i++)
 	{
 	{
 		float total = 0;
 		float total = 0;
 		int j;
 		int j;
-		for (j = 0; j < stbir__get_horizontal_contributors(stbir_info); j++)
+		for (j = 0; j < num_contributors; j++)
 		{
 		{
 			if (i >= stbir_info->horizontal_contributors[j].n0 && i <= stbir_info->horizontal_contributors[j].n1)
 			if (i >= stbir_info->horizontal_contributors[j].n0 && i <= stbir_info->horizontal_contributors[j].n1)
 			{
 			{
@@ -816,7 +817,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
 
 
 		float scale = 1 / total;
 		float scale = 1 / total;
 
 
-		for (j = 0; j < stbir__get_horizontal_contributors(stbir_info); j++)
+		for (j = 0; j < num_contributors; j++)
 		{
 		{
 			if (i >= stbir_info->horizontal_contributors[j].n0 && i <= stbir_info->horizontal_contributors[j].n1)
 			if (i >= stbir_info->horizontal_contributors[j].n0 && i <= stbir_info->horizontal_contributors[j].n1)
 				*stbir__get_coefficient(stbir_info, j, i - stbir_info->horizontal_contributors[j].n0) *= scale;
 				*stbir__get_coefficient(stbir_info, j, i - stbir_info->horizontal_contributors[j].n0) *= scale;
@@ -824,6 +825,15 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
 				break;
 				break;
 		}
 		}
 	}
 	}
+
+	// Using min to avoid writing into invalid pixels.
+	for (i = 0; i < num_contributors; i++)
+	{
+		stbir__contributors* contributors = &stbir_info->horizontal_contributors[i];
+		STBIR__DEBUG_ASSERT(contributors->n1 >= contributors->n0);
+
+		contributors->n1 = stbir__min(contributors->n1, stbir_info->output_w - 1);
+	}
 }
 }
 
 
 // Each scan line uses the same kernel values so we should calculate the kernel
 // Each scan line uses the same kernel values so we should calculate the kernel
@@ -1014,6 +1024,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
 		{
 		{
 			int decode_pixel_index = x * channels;
 			int decode_pixel_index = x * channels;
 			float alpha = decode_buffer[decode_pixel_index + alpha_channel];
 			float alpha = decode_buffer[decode_pixel_index + alpha_channel];
+
+			if (alpha == 0)
+				alpha = decode_buffer[decode_pixel_index + alpha_channel] = (float)1 / 17179869184; // 1/2^34 should be small enough that it won't affect anything.
+
 			for (c = 0; c < channels; c++)
 			for (c = 0; c < channels; c++)
 			{
 			{
 				if (c == alpha_channel)
 				if (c == alpha_channel)
@@ -1129,12 +1143,10 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
 
 
 		int in_x = x - filter_pixel_margin;
 		int in_x = x - filter_pixel_margin;
 		int in_pixel_index = in_x * channels;
 		int in_pixel_index = in_x * channels;
-		int max_n = stbir__min(n1, output_w-1);
+		int max_n = n1;
 		int coefficient_group = x*kernel_pixel_width;
 		int coefficient_group = x*kernel_pixel_width;
 
 
-		STBIR__DEBUG_ASSERT(n1 >= n0);
-
-		// Using min and max to avoid writing into invalid pixels.
+		// Using max to avoid writing into invalid pixels.
 		for (k = stbir__max(n0, 0); k <= max_n; k++)
 		for (k = stbir__max(n0, 0); k <= max_n; k++)
 		{
 		{
 			int coefficient_index = (k - n0) + coefficient_group;
 			int coefficient_index = (k - n0) + coefficient_group;
@@ -1199,8 +1211,8 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
 			int output_pixel_index = x*channels;
 			int output_pixel_index = x*channels;
 			int encode_pixel_index = x*channels;
 			int encode_pixel_index = x*channels;
 			float alpha = encode_buffer[encode_pixel_index + alpha_channel];
 			float alpha = encode_buffer[encode_pixel_index + alpha_channel];
+			STBIR__DEBUG_ASSERT(alpha > 0);
 			float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
 			float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
-			// @TODO: if final alpha=0, we actually want to have ignored alpha... set alpha to sRGB_to_linear(1/255)/(2^24) so floats will discard it?
 			for (n = 0; n < channels; n++)
 			for (n = 0; n < channels; n++)
 				if (n != alpha_channel)
 				if (n != alpha_channel)
 					encode_buffer[encode_pixel_index + n] *= reciprocal_alpha;
 					encode_buffer[encode_pixel_index + n] *= reciprocal_alpha;

+ 46 - 11
tests/resample_test.cpp

@@ -384,18 +384,21 @@ void test_subpixel(const char* file, float width_percent, float height_percent,
 	free(output_data);
 	free(output_data);
 }
 }
 
 
-unsigned char* pixel(unsigned char* buffer, int x, int y, int c, int w, int n)
+unsigned int* pixel(unsigned int* buffer, int x, int y, int c, int w, int n)
 {
 {
 	return &buffer[y*w*n + x*n + c];
 	return &buffer[y*w*n + x*n + c];
 }
 }
 
 
 void test_premul()
 void test_premul()
 {
 {
-	unsigned char input[2 * 2 * 4];
-	unsigned char output[1 * 1 * 4];
+	unsigned int input[2 * 2 * 4];
+	unsigned int output[1 * 1 * 4];
+	unsigned int output2[2 * 2 * 4];
 
 
 	memset(input, 0, sizeof(input));
 	memset(input, 0, sizeof(input));
 
 
+	// First a test to make sure premul is working properly.
+
 	// Top left - solid red
 	// Top left - solid red
 	*pixel(input, 0, 0, 0, 2, 4) = 255;
 	*pixel(input, 0, 0, 0, 2, 4) = 255;
 	*pixel(input, 0, 0, 3, 2, 4) = 255;
 	*pixel(input, 0, 0, 3, 2, 4) = 255;
@@ -412,18 +415,50 @@ void test_premul()
 	*pixel(input, 1, 1, 1, 2, 4) = 255;
 	*pixel(input, 1, 1, 1, 2, 4) = 255;
 	*pixel(input, 1, 1, 3, 2, 4) = 25;
 	*pixel(input, 1, 1, 3, 2, 4) = 25;
 
 
-	stbir_resize_uint8_generic(input, 2, 2, 0, output, 1, 1, 0, 4, 3, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, &g_context);
+	stbir_resize(input, 2, 2, 0, output, 1, 1, 0, STBIR_TYPE_UINT32, 4, 3, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, &g_context);
 
 
-	float r = 1.0f;
-	float g = 1.0f;
-	float ra = 1.0;
-	float ga = (float)25 / 255;
+	float r = (float)255 / 4294967296;
+	float g = (float)255 / 4294967296;
+	float ra = (float)255 / 4294967296;
+	float ga = (float)25 / 4294967296;
 	float a = (ra + ga) / 2;
 	float a = (ra + ga) / 2;
 
 
-	STBIR_ASSERT(output[0] == (int)(r * ra / 2 / a * 255 + 0.5f)); // 232
-	STBIR_ASSERT(output[1] == (int)(g * ga / 2 / a * 255 + 0.5f)); // 23
+	STBIR_ASSERT(output[0] == (int)(r * ra / 2 / a * 4294967296 + 0.5f)); // 232
+	STBIR_ASSERT(output[1] == (int)(g * ga / 2 / a * 4294967296 + 0.5f)); // 23
 	STBIR_ASSERT(output[2] == 0);
 	STBIR_ASSERT(output[2] == 0);
-	STBIR_ASSERT(output[3] == (int)(a * 255 + 0.5f)); // 140
+	STBIR_ASSERT(output[3] == (int)(a * 4294967296 + 0.5f)); // 140
+
+	// Now a test to make sure it doesn't clobber existing values.
+
+	// Top right - completely transparent green
+	*pixel(input, 1, 0, 1, 2, 4) = 255;
+	*pixel(input, 1, 0, 3, 2, 4) = 0;
+
+	// Bottom right - completely transparent green
+	*pixel(input, 1, 1, 1, 2, 4) = 255;
+	*pixel(input, 1, 1, 3, 2, 4) = 0;
+
+	stbir_resize(input, 2, 2, 0, output2, 2, 2, 0, STBIR_TYPE_UINT32, 4, 3, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, &g_context);
+
+	STBIR_ASSERT(*pixel(output2, 0, 0, 0, 2, 4) == 255);
+	STBIR_ASSERT(*pixel(output2, 0, 0, 1, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 0, 0, 2, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 0, 0, 3, 2, 4) == 255);
+
+	STBIR_ASSERT(*pixel(output2, 0, 1, 0, 2, 4) == 255);
+	STBIR_ASSERT(*pixel(output2, 0, 1, 1, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 0, 1, 2, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 0, 1, 3, 2, 4) == 255);
+
+	STBIR_ASSERT(*pixel(output2, 1, 0, 0, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 1, 0, 1, 2, 4) == 255);
+	STBIR_ASSERT(*pixel(output2, 1, 0, 2, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 1, 0, 3, 2, 4) == 0);
+
+	STBIR_ASSERT(*pixel(output2, 1, 1, 0, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 1, 1, 1, 2, 4) == 255);
+	STBIR_ASSERT(*pixel(output2, 1, 1, 2, 2, 4) == 0);
+	STBIR_ASSERT(*pixel(output2, 1, 1, 3, 2, 4) == 0);
 }
 }
 
 
 // test that splitting a pow-2 image into tiles produces identical results
 // test that splitting a pow-2 image into tiles produces identical results