Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

more efficient QOI_RUN code #53

Closed

Conversation

oscardssmith
Copy link

Uses the approach shown in https://github.com/phoboslab/qoi/pull/41/files.
This gives 3% better compression for screenshots and 2% better for misc (no changes for photos). In addition, encoding and decoding are both sped up.

@oscardssmith
Copy link
Author

The second set of changes here are really good also. I moved QOI_RUN to be 4 bit tag, 4 bit data and make QOI_GDIFF have a 2 bit tag. This results in a further 2% average increase in compression ratio and this gain helps every type of file.

old: compression ratio
all: 4.3272
kodac: 2.1937
misc: 8.6941
screenshots: 13.2152
textures: 2.8293
wallpaper: 3.5999

new: compression ratio
all: 4.4080
kodac: 2.2787
misc: 8.7047
screenshots: 13.2750
textures: 2.9693
wallpaper: 3.6618

qoi.h Outdated Show resolved Hide resolved
@MrSmile
Copy link

MrSmile commented Dec 3, 2021

Implementation looks too overcomplicated for me. I think this approach is simpler:

diff --git a/qoi.h b/qoi.h
index 0aec728..794e0ea 100644
--- a/qoi.h
+++ b/qoi.h
@@ -401,22 +401,17 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
 			run++;
 		}
 
 		if ( 
 			run > 0 && 
-			(run == 0x2020 || px.v != px_prev.v || px_pos == px_end)
+			(px.v != px_prev.v || px_pos == px_end)
 		) {
-			if (run < 33) {
+			do {
 				run -= 1;
-				bytes[p++] = QOI_RUN_8 | run;
-			}
-			else {
-				run -= 33;
-				bytes[p++] = QOI_RUN_16 | run >> 8;
-				bytes[p++] = run;
-			}
-			run = 0;
+				bytes[p++] = QOI_RUN_8 | (run & 0x1f);
+				run >>= 5;
+			} while (run);
 		}
 
 		if (px.v != px_prev.v) {
 			int index_pos = QOI_COLOR_HASH(px) % 64;
 
@@ -517,53 +512,55 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
 	}
 
 	qoi_rgba_t px = {.rgba = {.r = 0, .g = 0, .b = 0, .a = 255}};
 	qoi_rgba_t index[64] = {0};
 
-	int run = 0;
+	int run = 0, run_shift = 0;
 	int chunks_len = size - QOI_PADDING;
 	for (int px_pos = 0; px_pos < px_len; px_pos += channels) {
 		if (run > 0) {
 			run--;
 		}
 		else if (p < chunks_len) {
 			int b1 = bytes[p++];
 
 			if ((b1 & QOI_MASK_2) == QOI_INDEX) {
 				px = index[b1 ^ QOI_INDEX];
+				run_shift = 0;
 			}
 			else if ((b1 & QOI_MASK_3) == QOI_RUN_8) {
-				run = (b1 & 0x1f);
-			}
-			else if ((b1 & QOI_MASK_3) == QOI_RUN_16) {
-				int b2 = bytes[p++];
-				run = (((b1 & 0x1f) << 8) | (b2)) + 32;
+				run = (((b1 & 0x1f) + 1) << run_shift) - 1;
+				run_shift += 5;
 			}
 			else if ((b1 & QOI_MASK_2) == QOI_DIFF_8) {
 				px.rgba.r += ((b1 >> 4) & 0x03) - 2;
 				px.rgba.g += ((b1 >> 2) & 0x03) - 2;
 				px.rgba.b += ( b1       & 0x03) - 2;
+				run_shift = 0;
 			}
 			else if ((b1 & QOI_MASK_3) == QOI_DIFF_16) {
 				int b2 = bytes[p++];
 				px.rgba.r += (b1 & 0x1f) - 16;
 				px.rgba.g += (b2 >> 4)   -  8;
 				px.rgba.b += (b2 & 0x0f) -  8;
+				run_shift = 0;
 			}
 			else if ((b1 & QOI_MASK_4) == QOI_DIFF_24) {
 				int b2 = bytes[p++];
 				int b3 = bytes[p++];
 				px.rgba.r += (((b1 & 0x0f) << 1) | (b2 >> 7)) - 16;
 				px.rgba.g +=  ((b2 & 0x7c) >> 2) - 16;
 				px.rgba.b += (((b2 & 0x03) << 3) | ((b3 & 0xe0) >> 5)) - 16;
 				px.rgba.a +=   (b3 & 0x1f) - 16;
+				run_shift = 0;
 			}
 			else if ((b1 & QOI_MASK_4) == QOI_COLOR) {
 				if (b1 & 8) { px.rgba.r = bytes[p++]; }
 				if (b1 & 4) { px.rgba.g = bytes[p++]; }
 				if (b1 & 2) { px.rgba.b = bytes[p++]; }
 				if (b1 & 1) { px.rgba.a = bytes[p++]; }
+				run_shift = 0;
 			}
 
 			index[QOI_COLOR_HASH(px) % 64] = px;
 		}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants