View Single Post
Old 04-20-2012, 01:17 PM   #22
geekmaster
Carpe diem, c'est la vie.
geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.geekmaster ought to be getting tired of karma fortunes by now.
 
geekmaster's Avatar
 
Posts: 6,433
Karma: 10773670
Join Date: Nov 2011
Location: Multiverse 6627A
Device: K1 to PW3
Arrow paldemo - kindle 0-255 dithered palette display

UPDATE: The new paldemo version (not yet published) contains a second dither table with gamma 2.2 dither threshold values for LCD and CRT desktop displays. This gives a color palette screenshot that appears correctly balanced (average 50% gray) on desktop displays. See the gamma tutorial below.

This "paldemo" program demonstrates the new "geekmaster formula 42" dithering function adapted for a 0-255 color palette. It can be used to convert a framebuffer containing a grayscale image or antialiased text directly to dithered black and white, so that it can be animated or resized smoothly.

A new dither table is used that spreads the 65 shades of gray evenly through the 0-255 color value range, and a "-1" adjustment was made to a strategic location in the formula to balance the number of pure blacks and pure whites on the ends of the color table for 4-bit pixel displays.

Because 65 is not a power of 2, the threshold columns do not line up in the displayed 16x16 color palette, but this is to be expected for non-integral range conversion.

The display palette onscreen size is adjustable. This demo program calls palette(550) to display a 550x550 pixel palette, but you can change that value to resize the palette.


The screenshot gamma tutorial:
Spoiler:
This image has a display gamma of 1.0 needed for kindle eink displays (just like printing on paper). CRT and LCD displays are typically adjusted for gamma 2.2, so this screenshot appears as a well-balanced color spread on the kindle, but viewing this on a CRT or LCD panel will show too many brights and not enough darks. That is to be expected, and adds another complication if you want a program to work on both eink and on LCD panels.

The DARK values are strongly affected by the gamma settings. Compare this image on an LCD panel (like you are probably viewing it on now) with the image displayed on a kindle eink display. Pay careful attention to the top five rows. On a kindle eink display, the entire top five rows of this image are black or "almost black". If you do not see what I am describing, your web browser probably converted the image to grayscale (with gamma correction) if it resized the image. View the image at "original size" and then compare it to the same image on the kindle. When viewed at the correct screen size, it will contain ONLY pure black and white pixels.

Gamma adjustments must be made by selecting dither tables with DIFFERENT threshold values for eink and LCD displays. The proper way to take a screenshot is to re-dither the 256-color image using an LCD dither table, and capture that. The image below uses an eink dither table. I will add another screenshot after I build an LCD dither table for my "paldemo" program.

An image dithered with an LCD dither table will look good on this web page, but will look MUCH TOO DARK on a kindle eink display. You need to use a dither table with threshold values that match your intended display device.

eink gamma 1.0 (linear distribution) dither table:


lcd gamma 2.2 (exponential distribution) dither table:


The source:
Spoiler:
PHP Code:
//====================================================
// paldemo 1.0 - kindle 0-255 dithered palette display
// Copyright (C) 2012 by geekmaster, with MIT license:
// http://www.opensource.org/licenses/mit-license.php
//----------------------------------------------------
//  The speed is limited by the eink device drivers.
//  Newer kindle models are faster, but need delays.
//  This was tested on DX,DXG,K3,K4(Mini),K5(Touch).
//----------------------------------------------------

#include <stdio.h>      // printf
#include <stdlib.h>    // malloc, free, atoi
#include <string.h>   // memset, memcpy
#include <unistd.h>  // usleep
#include <fcntl.h>  // open, close, write
#include <time.h>  // time
#include <sys/ioctl.h>   // ioctl
#include <sys/time.h>   // gettime
#include <sys/mman.h>  // mmap, munmap
#include <linux/fb.h> // screeninfo

#define FPS 5 // max frames/sec

enum eupd_op EUPD_OPEN,EUPD_CLOSE,EUPD_UPDATE };
typedef unsigned char u8;
typedef unsigned int u32;

// function prototypes
inline void setpx(int,int,int);
int eupdate(int);
int getmsec(void);
void palette(int);

// global var7
u32 mpu=100;      // msec/update
u8 *fb0=NULL;   // framebuffer pointer
int fdFB=0;    // fb0 file descriptor
u32 fs=0;     // fb0 stride
u32 MX=0;    // xres (visible)
u32 MY=0;   // yres (visible)
u8 blk=0;  // black
u8 wht=0// white
u8 pb=0// pixel bits

//================================================
// paldemo - kindle 0-255 dithered palette display
// This works on all kindle eink models.   Enjoy!
//------------------------------------------------
void paldemo(void) {
    
int x,y,c,tn,i,j;
    
struct fb_var_screeninfo screeninfo;
    
fdFB=open("/dev/fb0",O_RDWR); // eink framebuffer

// calculate model-specific vars
    
ioctl(fdFB,FBIOGET_VSCREENINFO,&screeninfo);
    
MX=screeninfo.xres;  // max X+1
    
MY=screeninfo.yres// max Y+1
    
pb=screeninfo.bits_per_pixel;     // pixel bits
    
fs=screeninfo.xres_virtual*pb/8// fb0 stride
    
blk=pb/8-1// black
    
wht=~blk;  // white
    
fb0=(u8 *)mmap(0,MY*fs,PROT_READ|PROT_WRITE,MAP_SHARED,fdFB,0); // map fb0
    
eupdate(EUPD_OPEN); // open fb0 update proc

    
system("eips 19 32 '0-255 Palette'");
    
system("eips 19 34 'by Geekmaster'");

    
palette(550);

// cleanup - close and free resources
    
eupdate(EUPD_UPDATE);    // update display
    
eupdate(EUPD_CLOSE);    // close fb0 update proc port
    
munmap(fb0,fs*(MY+1)); // unmap fb0
    
close(fdFB);          // close fb0
}

//=========================================
// palette - display scaled "color" palette
//-----------------------------------------
void palette(int s) {
    
int x,y,c;
    for (
y=(MX-s)/2;y<(MX+s)/2;y++) for (x=(MX-s)/2;x<(MX+s)/2;x++) {
        
c=(y-(MX-s)/2)*16/s*16+(((x-(MX-s)/2)*16)/s);
        
setpx(x,y,c);
    }
}

//===============================
// eupdate - eink update display
// op (open, close, update)
//-------------------------------
int eupdate(int op) {
    static 
int fdUpdate=-1;
    if (
EUPD_OPEN==op) { fdUpdate=open("/proc/eink_fb/update_display",O_WRONLY);
    } else if (
EUPD_CLOSE==op) { close(fdUpdate);
    } else if (
EUPD_UPDATE==op) {
        if (-
1==fdUpdate) { system("eips ''");
        } else { 
write(fdUpdate,"1\n",2); }
    } else { return -
1; } // bad op code
    
return fdUpdate;
}

//========================================
// setpx - draw pixel using ordered dither
// x,y:screen coordinates, c:color(0-255).
// (This works on all eink kindle models.)
//----------------------------------------
inline void setpx(int x,int y,int c) {
    static 
int dt[64] = {
    
3,129,34,160,10,136,42,168,192,66,223,97,200,73,231,105,50,
    
176,18,144,58,184,26,152,239,113,207,81,247,121,215,89,14,
    
140,46,180,7,133,38,164,203,77,235,109,196,70,227,101,62,188,
    
30,156,54,180,22,148,251,125,219,93,243,117,211,85 }; // 0-255 dither table
    
fb0[pb*x/8+fs*y]=((256&(c-dt[(7&x)+8*(7&y)]-1))/256*(blk&(240*(1&~x)|
        
15*(1&x)|fb0[pb*x/8+fs*y])))|((256&(dt[(7&x)+8*(7&y)]-c))/256*wht|
        (
blk&((240*(1&x)|15*(1&~x))&fb0[pb*x/8+fs*y]))); // geekmaster formula 42
}

//====================================
// getmsec - get msec since first call
// (tick counter wraps every 12 days)
//------------------------------------
int getmsec(void) {
    
int tc;
    static 
int ts=0;
    
struct timeval tv;
    
gettimeofday(&tv,NULL); tc=tv.tv_usec/1000+1000*(0xFFFFF&tv.tv_sec);
    if (
0==tc) { ts=tc; }
    return 
tc-ts;
}

//==================
// main - start here
//------------------
int main(int argc,char **argv) {
    if (
argc>1) { mpu=atoi(argv[1]); }
    
paldemo(); // display 0-255 dithered palette
    
return 0;


The download:
Attached Files
File Type: gz paldemo.tar.gz (6.8 KB, 292 views)

Last edited by geekmaster; 04-21-2012 at 11:44 AM.
geekmaster is offline   Reply With Quote