Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * mkconvert
- * =========
- *
- * Written 2012 by Magnus Kalkuhl
- *
- * magnus.kalkuhl@kaspersky.com
- * http://twitter.com/magnuskalkuhl
- *
- * For "About", "Important to know", "Disclaimer" and
- * "Redistribution" rules please check the text in the main() section.
- *
- * COMPILATION (ON UBUNTU LINUX)
- * -----------------------------
- *
- * - Install required GD library: sudo apt-get install libgd2-xpm-dev
- * - Compile with: gcc -std=c99 mkconvert.c -o mkconvert -lgd
- *
- * USAGE
- * -----
- *
- * ./mkconvert <source directory> <target directory>
- *
- * USEFUL LINKS
- * ------------
- *
- * - Libre office extension to export slides as PNG files:
- * http://extensions.libreoffice.org/extension-center/export-as-images
- * Ensure you disable antialiasing in Libre Office
- * (Tools -> Options -> LibreOffice -> View)
- * or text edges will look fuzzy.
- *
- * - Original mkviewer and the presentation it was used for:
- * http://t.co/csih7QtO
- *
- * - Editor for C64 disk images: http://www.d64editor.com
- * Windows only :(
- *
- */
- #include <stdio.h>
- #include <gd.h>
- #include <dirent.h>
- #include <string.h>
- #define WIDTH 320
- #define HEIGHT 200
- #define PATH_MAX 4096
- int grayscaleImage[WIDTH*HEIGHT];
- int c64bitmap[(WIDTH*HEIGHT)/8];
- int importFileAsGrayscale(char *sourceName)
- {
- // Read PNG file and turn colors into gray scale luminance
- // (range from black to white: 0 - 255)
- gdImagePtr im;
- FILE *in;
- in = fopen(sourceName, "rb");
- if (in == NULL)
- {
- printf("Failed to open image '%s'!\n",sourceName);
- return -1;
- }
- im = gdImageCreateFromPng(in);
- fclose(in);
- if (gdImageSX(im) != WIDTH || gdImageSY(im) != HEIGHT)
- {
- printf("Wrong size of '%s' (should be %i x %i, but has %i x %i)\n",
- sourceName,WIDTH,HEIGHT, gdImageSX(im),gdImageSY(im));
- return -1;
- }
- // Import image
- for (int y = 0; y < HEIGHT; y++)
- {
- for (int x = 0; x < WIDTH; x++)
- {
- int c;
- c = gdImageGetPixel(im, x, y);
- grayscaleImage[y*WIDTH+x] = (gdImageRed(im, c)+gdImageGreen(im, c)+gdImageBlue(im, c))/3;
- }
- }
- gdImageDestroy(im);
- return 0;
- }
- void ditherGrayScaleIntoBlackAndWhite()
- {
- // Dither grayscale image into black (0) and white (255) pixels
- for (int y = 0; y < HEIGHT; y++)
- {
- for (int x = 0; x < WIDTH; x++)
- {
- int cMix = grayscaleImage[y*WIDTH+x];
- int cNew;
- int level = 0;
- if (cMix > 100) level = 1;
- if (cMix > 120) level = 2;
- if (cMix > 140) level = 3;
- if (cMix > 160) level = 4;
- if (level == 0) cNew = 0;
- if (level == 1)
- {
- cNew = 0;
- if ((x & 1) == 0 && (y & 1) == 0) cNew = 255;
- }
- if (level == 2)
- {
- cNew = 0;
- if (((x+y) & 1) == 0) cNew = 255;
- }
- if (level == 3)
- {
- cNew = 255;
- if ((x & 1) == 1 && (y & 1) == 0) cNew = 0;
- }
- if (level == 4) cNew = 255;
- grayscaleImage[y*WIDTH+x] = cNew;
- }
- }
- }
- void convertBlackWhiteImageIntoC64Bitmap()
- {
- // Convert black/white image into real C64 bitmap
- /* Some words about C64 bitmaps:
- * Each byte contains 8 pixel (from left to right).
- * After each byte, line increases by one.
- * After eight bytes, line decreases by 8 and column increases by 8
- *
- * See below:
- *
- * BYTE PIXELS ON SCREEN
- * 00 Line 0, Columns 0-7
- * 01 Line 1, Columns 0-7
- * 02 Line 2, Columns 0-7
- * 03 Line 3, Columns 0-7
- * 04 Line 4, Columns 0-7
- * 05 Line 5, Columns 0-7
- * 06 Line 6, Columns 0-7
- * 07 Line 7, Columns 0-7
- * 08 Line 0, Columns 8-15
- * 09 Line 1, Columns 8-15
- * 10 Line 2, Columns 8-15
- * 11 Line 3, Columns 8-15
- * ...
- */
- int xc = 0;
- int yc = 0;
- int subLine = 0;
- for (int i = 0; i < ((WIDTH*HEIGHT)/8); i++)
- {
- c64bitmap[i] =
- ((grayscaleImage[(yc+subLine)*WIDTH+xc+0] & 1) << 7)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+1] & 1) << 6)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+2] & 1) << 5)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+3] & 1) << 4)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+4] & 1) << 3)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+5] & 1) << 2)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+6] & 1) << 1)
- + ((grayscaleImage[(yc+subLine)*WIDTH+xc+7] & 1) << 0);
- subLine++;
- if (subLine == 8)
- {
- subLine = 0;
- xc = xc + 8;
- if (xc == WIDTH)
- {
- xc = 0;
- yc = yc + 8;
- }
- }
- }
- }
- int compressC64Bitmap(char *targetName)
- {
- /*
- * Some words about the proprietary .pk image format:
- *
- * First two bytes: The start address ($00 $04 -> $4000) of the file
- *
- * All other bytes contain the image data:
- *
- * - Any value that is NOT 123 is taken as it is
- * (1 Byte -> 8 Pixels, from left to right)
- * - magic byte "123" (0x7B) + n -> repeat the previous byte n times
- * (n is never 0 or 1 here)
- * - magic byte 123 + 0 -> byte 123
- * - magic byte 123 + 1 -> end of file
- *
- */
- FILE *out;
- char compressedName[1000];
- sprintf(compressedName,"%s.pk",targetName);
- out = fopen(compressedName,"wb");
- if (out == NULL)
- {
- printf("Failed to create '%s'\n",compressedName);
- return -1;
- }
- // Ensure that the file is going to be loaded at $4000
- fputc(0x00,out); fputc(0x40,out);
- int lastCol = 0;
- int i = 0;
- while (i < (WIDTH*HEIGHT)/8)
- {
- // in case the color value matches the "magic byte" (123) accidentally
- if (c64bitmap[i] == 123)
- {
- fputc(123,out);
- fputc(0,out);
- lastCol = 123;
- i++;
- continue;
- }
- // find sequence of repeating bytes
- int sequenceCounter = 0;
- while (c64bitmap[i+sequenceCounter] == lastCol && sequenceCounter < 255) sequenceCounter++;
- if (sequenceCounter >= 3)
- {
- fputc(123,out);
- fputc(sequenceCounter-1,out);
- i = i + sequenceCounter;
- continue;
- }
- if (sequenceCounter > 0)
- {
- for (int p = 0; p < sequenceCounter; p++) fputc(lastCol,out);
- i = i + sequenceCounter;
- continue;
- }
- // Standard: normal byte
- fputc(c64bitmap[i],out);
- lastCol = c64bitmap[i];
- i++;
- }
- fputc(123,out); fputc(1,out); // write end-marker
- fclose(out);
- printf("Created %s\n",targetName);
- return 0;
- }
- int createImageForValidation(char *targetName)
- {
- // Recreate PNG image from C64 bitmap
- gdImagePtr im;
- im = gdImageCreateTrueColor(WIDTH,HEIGHT);
- int xc = 0;
- int yc = 0;
- int subLine = 0;
- for (int i = 0; i < ((WIDTH*HEIGHT)/8); i++)
- {
- int v; int c;
- int byte = c64bitmap[i];
- v = ((byte >> 7) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+0, yc+subLine, c);
- v = ((byte >> 6) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+1, yc+subLine, c);
- v = ((byte >> 5) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+2, yc+subLine, c);
- v = ((byte >> 4) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+3, yc+subLine, c);
- v = ((byte >> 3) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+4, yc+subLine, c);
- v = ((byte >> 2) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+5, yc+subLine, c);
- v = ((byte >> 1) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+6, yc+subLine, c);
- v = ((byte >> 0) & 1)*255; c = gdTrueColor(v,v,v); gdImageSetPixel(im, xc+7, yc+subLine, c);
- subLine++;
- if (subLine == 8)
- {
- subLine = 0;
- xc = xc + 8;
- if (xc == WIDTH)
- {
- xc = 0;
- yc = yc + 8;
- }
- }
- }
- char extendedTargetName[500];
- sprintf(extendedTargetName,"%s.png",targetName);
- FILE *out = fopen(extendedTargetName,"wb");
- if (out == NULL)
- {
- printf("Failed to create %s\n",extendedTargetName);
- gdImageDestroy(im);
- return -1;
- }
- gdImagePng(im, out);
- fclose(out);
- gdImageDestroy(im);
- return 0;
- }
- int processPic(char *sourceName,char *targetName)
- {
- if (importFileAsGrayscale(sourceName) != 0) return -1;
- ditherGrayScaleIntoBlackAndWhite();
- convertBlackWhiteImageIntoC64Bitmap();
- if (compressC64Bitmap(targetName) != 0) return -1;
- if (createImageForValidation(targetName) != 0) return -1;
- return 0;
- }
- int processDirectory(char *sourcePath, char *targetPath)
- {
- DIR *directoryPointer = opendir(sourcePath);
- struct dirent *files;
- if (directoryPointer == NULL)
- {
- printf("Failed opening dir %s\n",sourcePath);
- return -1;
- }
- char newp[PATH_MAX];
- while ((files=readdir(directoryPointer))!=NULL)
- {
- if (!strcmp(files->d_name,".") || !strcmp(files->d_name,"..")) continue;
- if ((strlen(sourcePath)+strlen(files->d_name)+1) >= PATH_MAX)
- {
- printf("Won't read '%s/%s' as it exceeds the max. path length (%i characters).\n",sourcePath,files->d_name,PATH_MAX-1);
- continue;
- }
- sprintf(newp,"%s/%s",sourcePath,files->d_name);
- int c1 = files->d_name[strlen(files->d_name)-6]-'0';
- int c2 = files->d_name[strlen(files->d_name)-5]-'0';
- int slideNumber = (c1*10+c2);
- if (slideNumber < 1) printf("Invalid slide name: %s (expected format: NN.png, e.g. 01.png)\n", files->d_name);
- else
- {
- if ((strlen(sourcePath)+strlen(files->d_name)+1) >= PATH_MAX)
- {
- printf("Won't write '%s/%s' as it exceeds the max. path length (%i characters).\n",sourcePath,files->d_name,PATH_MAX-1);
- continue;
- }
- char outPath[PATH_MAX];
- sprintf(outPath,"%s/%.2i",targetPath,slideNumber);
- processPic(newp,outPath);
- }
- }
- closedir(directoryPointer);
- return 0;
- }
- int main(int argc, char *argv[])
- {
- if (argc == 3) return processDirectory(argv[1],argv[2]);
- printf("Usage: mkconvert <source directory> <target directory>\n");
- printf(" e.g. mkconvert src out\n");
- printf(" or mkconvert --help (for disclaimer, redistribution rules etc.)\n");
- printf("\n");
- if (argc == 2)
- {
- if (strcmp(argv[1],"--help") == 0 || strcmp(argv[1],"--about") == 0)
- {
- printf("About:\n");
- printf("\"mkconvert\" was written 2012 by Magnus Kalkuhl <magnus.kalkuhl@kaspersky.com>.\n");
- printf("This program reads PNG images from \"src\" directory and converts them\n");
- printf("into the proprietary .pk format that can then be read by the mkviewer on the C64.\n");
- printf("\n");
- printf("Important to know:\n");
- printf("- All source files must be named 01.png, 02.png, 03.png etc.\n");
- printf("- All source files must have a resolution of 320x200 pixel.\n");
- printf("\n");
- printf("Disclaimer:\n");
- printf("I developed this program as a quick and dirty one-time-tool for a\n");
- printf("presentation I did (see https://twitter.com/magnuskalkuhl/status/251697621931028480).\n");
- printf("It is in no way an official software release and therefore comes without any guarantees.\n");
- printf("Use at your own risk.\n");
- printf("\n");
- printf("Redistribution:\n");
- printf("Feel free to redistribute this program or improve it\n");
- printf("as long as the information about author, disclaimer and redistribution remains.\n");
- printf("\n");
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement