diff --git a/osufs/osufs/imgenc.c b/osufs/osufs/imgenc.c
index 66f3163d9f94c3bcb169efeadd427f546fe8ae58..46c89d6b0e40ad17c5afbdbea272a7247101d54a 100644
--- a/osufs/osufs/imgenc.c
+++ b/osufs/osufs/imgenc.c
@@ -80,7 +80,86 @@ uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr) {
 	return addr;
 }
 
-uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, uint16_t *w, uint16_t *h) {
+uint32_t img_write_dither64(const char *filename, mdev *dev, uint32_t addr,
+							uint16_t *w, uint16_t *h) {
+	char cbuf[1024];
+	int ret;
+	
+	int w_signed = *w==0xffff ? -1 : *w, h_signed = *h==0xffff ? -1 : *h;
+	
+	system("rm -f /tmp/source.png /tmp/plt.png /tmp/dither.png");
+	
+	// Resize
+	sprintf(cbuf, "ffmpeg -loglevel error -i \"%s\" -vf \"scale=%d:%d\" /tmp/source.png", filename, w_signed, h_signed);
+	ret = system(cbuf);
+	if (ret != 0) {
+		fprintf(stderr, "ffmpeg resize failed with exit code: %d\n", ret);
+		return addr;
+	}
+	
+	// PaletteGen
+	ret = system("ffmpeg -loglevel error -i /tmp/source.png -vf \"palettegen=max_colors=64\" /tmp/plt.png");
+	if (ret != 0) {
+		fprintf(stderr, "ffmpeg palettegen failed with exit code: %d\n", ret);
+		return addr;
+	}
+	
+	// Dithering
+	ret = system("ffmpeg -loglevel error -i /tmp/source.png -i /tmp/plt.png -lavfi \"paletteuse=dither=floyd_steinberg\" -y /tmp/dither.png");
+	if (ret != 0) {
+		fprintf(stderr, "ffmpeg dithering failed with exit code: %d\n", ret);
+	}
+	
+	
+	PNGImage img = pngimg_read("/tmp/dither.png");
+	if (img.color_type != PNG_COLOR_TYPE_PALETTE) {
+		fprintf(stderr, "Internal Error: dithered image is not index!\n");
+		return addr;
+	}
+	
+	png_colorp plt;
+	int nplt;
+	if (!png_get_PLTE(img.png_ptr, img.info_ptr, &plt, &nplt)) {
+		fprintf(stderr, "Internal Error: failed to read palette!\n");
+		return addr;
+	}
+	
+	// Dump palette
+	uint8_t buf[512], *pltbuf = buf + 3;
+	buf[0] = 'P';
+	buf[1] = 'L';
+	buf[2] = 'T';
+	for (int i=0; i<64; i++) {
+		pltbuf[i*3+0] = plt[0xff-i].red;
+		pltbuf[i*3+1] = plt[0xff-i].green;
+		pltbuf[i*3+2] = plt[0xff-i].blue;
+	}
+	blkio_write(dev, addr++, buf);
+	
+	// Dump image, row major
+	*w = img.width;
+	*h = img.height;
+	printf("Saving pixels in %s\n", filename);
+	size_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height;
+	size_t bufptr = 0;
+	uint8_t *pixbuf;
+	while (bufsize > 0) {
+		pixbuf = img.row_pointers[0]+bufptr;
+		for (int i=0; i<512; i++) {
+			pixbuf[i] = 0xff - pixbuf[i];
+		}
+		blkio_write(dev, addr++, pixbuf);
+		bufptr += 512;
+		bufsize -= 512;
+	}
+	
+	pngimg_release(&img);
+	
+	return addr;
+}
+
+uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr,
+						 uint16_t *w, uint16_t *h) {
 	char cbuf[1024];
 	int ret;
 	
diff --git a/osufs/osufs/imgenc.h b/osufs/osufs/imgenc.h
index 1f49ea13d561d890a627f56b3a5651d3c3befda2..f0a0e948708398d20c34e233e81df70dee0cec0f 100644
--- a/osufs/osufs/imgenc.h
+++ b/osufs/osufs/imgenc.h
@@ -17,7 +17,10 @@ extern "C" {
 #include "blkio.h"
 	
 	uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr);
-	uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, uint16_t *w, uint16_t *h);
+	uint32_t img_write_dither64(const char *filename, mdev *dev, uint32_t addr,
+								uint16_t *w, uint16_t *h);
+	uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr,
+							 uint16_t *w, uint16_t *h);
 
 #ifdef __cplusplus
 }
diff --git a/osufs/osufs/osu.cpp b/osufs/osufs/osu.cpp
index 839798e5d3cc5acdd32effa3a93b8b5de3467ebc..9823a58b6529dd8932eaf5a1df62a216ac1888b7 100644
--- a/osufs/osufs/osu.cpp
+++ b/osufs/osufs/osu.cpp
@@ -39,6 +39,13 @@ meta-> entry ## _w = w;\
 meta-> entry ## _h = h;\
 addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## _h));
 	
+#define SKIN_IMPORT_IMAGE_DITHER64(entry, filename, w, h)\
+strcpy(fname, filename);\
+meta-> entry = addr;\
+meta-> entry ## _w = w;\
+meta-> entry ## _h = h;\
+addr = img_write_dither64(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## _h));
+	
 	char cbuf[1024], *fname;
 	uint32_t addr = meta->available_block;
 
@@ -98,16 +105,16 @@ addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ##
 	SKIN_IMPORT_IMAGE(pause_continue, "pause-continue.png", 235, -1)
 	SKIN_IMPORT_IMAGE(pause_retry, "pause-retry.png", 235, -1)
 
-	SKIN_IMPORT_IMAGE(ranking_ss, "ranking-X.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_s, "ranking-S.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_a, "ranking-A.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_b, "ranking-B.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_c, "ranking-C.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_d, "ranking-D.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_ss, "ranking-X.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_s, "ranking-S.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_a, "ranking-A.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_b, "ranking-B.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_c, "ranking-C.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_d, "ranking-D.png", 160, -1)
+	
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_title, "ranking-title.png", 240, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_panel, "ranking-panel.png", 378, -1)
 	
-//	SKIN_IMPORT_IMAGE(ranking_title, "ranking-title.png", 240, -1)
-//	SKIN_IMPORT_IMAGE(ranking_panel, "ranking-panel.png", 378, -1)
-
 	meta->selection_w = 48;
 	meta->selection_h = 56;
 	meta->selection_mod = addr;