Step #1 factoring out the frontend code

This is part of the split between C/C++/Lua API (backend)
and frontend code. External submodules are now part of the
backend code.
pull/2/merge
HW 11 years ago
parent 8ff9a1a98d
commit 364bf96f7a

3
.gitmodules vendored

@ -16,3 +16,6 @@
[submodule "libk2pdfopt"]
path = libk2pdfopt
url = git://github.com/chrox/libk2pdfopt.git
[submodule "koreader-base"]
path = koreader-base
url = git://github.com/hwhw/koreader-base.git

@ -1,867 +0,0 @@
/*
KindlePDFViewer: buffer for blitting muPDF data to framebuffer (blitbuffer)
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include "blitbuffer.h"
/* debugging statements, switch as needed */
#ifdef DEBUG
#define ASSERT_BLITBUFFER_BOUNDARIES(bb,bb_ptr) \
if((bb_ptr < bb->data) || (bb_ptr >= (bb->data + bb->pitch * bb->h))) { \
fprintf(stderr, "violated blitbuffer constraints in file %s, line %d!\r\n", __FILE__, __LINE__); exit(1); \
}
#else // DEBUG
#define ASSERT_BLITBUFFER_BOUNDARIES(bb,bb_ptr) {}
#endif // DEBUG
inline int getPixel(BlitBuffer *bb, int x, int y) {
uint8_t *dstptr = (uint8_t*)(bb->data) + (y * bb->pitch) + (x / 2);
ASSERT_BLITBUFFER_BOUNDARIES(bb, dstptr);
if(x % 2 == 0) {
return (*dstptr & 0xF0) >> 4;
} else {
return *dstptr & 0x0F;
}
}
inline void setPixel(BlitBuffer *bb, int x, int y, int c) {
uint8_t *dstptr = (uint8_t*)(bb->data) + (y * bb->pitch) + (x / 2);
ASSERT_BLITBUFFER_BOUNDARIES(bb, dstptr);
if(x % 2 == 0) {
*dstptr &= 0x0F;
*dstptr |= c << 4;
} else {
*dstptr &= 0xF0;
*dstptr |= c;
}
}
/*
* if ptich equals zero, we calculate it as (w + 1) / 2
*/
int newBlitBufferNative(lua_State *L, int w, int h, int pitch, BlitBuffer **newBuffer) {
BlitBuffer *bb = (BlitBuffer*) lua_newuserdata(L, sizeof(BlitBuffer));
luaL_getmetatable(L, "blitbuffer");
lua_setmetatable(L, -2);
bb->w = w;
bb->pitch = ((pitch == 0) ? ((w + 1) / 2) : pitch);
bb->h = h;
bb->data = malloc(bb->pitch * h);
if(bb->data == NULL) {
return luaL_error(L, "cannot allocate memory for blitbuffer");
}
memset(bb->data, 0, bb->pitch * h);
bb->allocated = 1;
if(newBuffer != NULL) {
*newBuffer = bb;
}
return 1;
}
static int newBlitBuffer(lua_State *L) {
int w = luaL_checkint(L, 1);
int h = luaL_checkint(L, 2);
int pitch = luaL_optint(L, 3, 0);
return newBlitBufferNative(L, w, h, pitch, NULL);
}
static int getWidth(lua_State *L) {
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
lua_pushinteger(L, bb->w);
return 1;
}
static int getHeight(lua_State *L) {
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
lua_pushinteger(L, bb->h);
return 1;
}
static int freeBlitBuffer(lua_State *L) {
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
// should be save if called twice
if(bb->allocated && bb->data != NULL) {
free(bb->data);
bb->data = NULL;
}
return 0;
}
static int blitFullToBuffer(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
if(src->w != dst->w || src->h != dst->h || src->pitch != dst->pitch) {
return luaL_error(L, "dst and src blitbuffer size not match!");
}
memcpy(dst->data, src->data, src->pitch * src->h);
return 0;
}
/**
* check/adapt boundaries for blitting operations
*
* @return 0 if no blitting is needed, 1 otherwise
*/
int fitBlitBufferBoundaries(BlitBuffer* src, BlitBuffer* dst, int* xdest, int* ydest, int* xoffs, int* yoffs, int* w, int* h) {
// check bounds
if(*ydest < 0) {
// negative ydest, try to compensate
if(*ydest + *h > 0) {
// shrink h by negative dest offset
*h += *ydest;
// extend source offset
*yoffs += -(*ydest);
*ydest = 0;
} else {
// effectively no height
return 0;
}
} else if(*ydest >= dst->h) {
// we're told to paint to off-bound target coords
return 0;
}
if(*ydest + *h > dst->h) {
// clamp height if too large for target size
*h = dst->h - *ydest;
}
if(*yoffs >= src->h) {
// recalculated source offset is out of bounds
return 0;
} else if(*yoffs + *h > src->h) {
// clamp height if too large for source size
*h = src->h - *yoffs;
}
// same stuff for x coords:
if(*xdest < 0) {
if(*xdest + *w > 0) {
*w += *xdest;
*xoffs += -(*xdest);
*xdest = 0;
} else {
return 0;
}
} else if(*xdest >= dst->w) {
return 0;
}
if(*xdest + *w > dst->w) {
*w = dst->w - *xdest;
}
if(*xoffs >= src->w) {
return 0;
} else if(*xoffs + *w > src->w) {
*w = src->w - *xoffs;
}
return 1; // continue processing
}
static int blitToBuffer(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
int xdest = luaL_checkint(L, 3);
int ydest = luaL_checkint(L, 4);
int xoffs = luaL_checkint(L, 5);
int yoffs = luaL_checkint(L, 6);
int w = luaL_checkint(L, 7);
int h = luaL_checkint(L, 8);
int x, y;
uint8_t *dstptr;
uint8_t *srcptr;
if(!fitBlitBufferBoundaries(src, dst, &xdest, &ydest, &xoffs, &yoffs, &w, &h))
return 0;
if(xdest & 1) {
/* this will render the leftmost column */
dstptr = (uint8_t*)(dst->data +
ydest * dst->pitch +
xdest / 2);
srcptr = (uint8_t*)(src->data +
yoffs * src->pitch +
xoffs / 2 );
if(xoffs & 1) {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
*dstptr &= 0xF0;
*dstptr |= *srcptr & 0x0F;
dstptr += dst->pitch;
srcptr += src->pitch;
}
} else {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
*dstptr &= 0xF0;
*dstptr |= *srcptr >> 4;
dstptr += dst->pitch;
srcptr += src->pitch;
}
}
xdest++;
xoffs++;
w--;
}
dstptr = (uint8_t*)(dst->data +
ydest * dst->pitch +
xdest / 2);
srcptr = (uint8_t*)(src->data +
yoffs * src->pitch +
xoffs / 2 );
if(xoffs & 1) {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
for(x = 0; x < (w / 2); x++) {
dstptr[x] = (srcptr[x] << 4) | (srcptr[x+1] >> 4);
}
if(w & 1) {
dstptr[x] &= 0x0F;
dstptr[x] |= srcptr[x] << 4;
}
dstptr += dst->pitch;
srcptr += src->pitch;
}
} else {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
memcpy(dstptr, srcptr, w / 2);
if(w & 1) {
dstptr[w/2] &= 0x0F;
dstptr[w/2] |= (srcptr[w/2] & 0xF0);
}
dstptr += dst->pitch;
srcptr += src->pitch;
}
}
return 0;
}
static int rotate_table[3][2] = {
/* cos, sin */
{0, 1}, /* 90 degree */
{-1, 0}, /* 180 degree */
{0, -1}, /* 270 degree */
};
/** @brief rotate and blit to buffer
*
* Currently, only support rotation of 90, 180, 270 degree.
* */
static int blitToBufferRotate(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
int degree = luaL_checkint(L, 3);
int i, j, x, y, /* src and dst coordinate */
x_adj = 0, y_adj = 0; /* value for translation after rotatation */
int cosT = rotate_table[degree/90-1][0],
sinT = rotate_table[degree/90-1][1],
u, v;
switch (degree) {
case 180:
y_adj = dst->h-1;
case 90:
x_adj = dst->w-1;
break;
case 270:
y_adj = dst->h-1;
break;
}
u = x_adj;
v = y_adj;
for (j = 0; j < src->h; j++) {
/*
* x = -sinT * j + x_adj;
* y = cosT * j + y_adj;
*/
x = u;
y = v;
for (i = 0; i < src->w; i++) {
/*
* each (i, j) maps to (x, y)
* x = cosT * i - sinT * j + x_adj;
* y = cosT * j + sinT * i + y_adj;
*/
setPixel(dst, x, y, getPixel(src, i, j));
x += cosT;
y += sinT;
}
u -= sinT;
v += cosT;
}
return 0;
}
static int addblitToBuffer(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
int xdest = luaL_checkint(L, 3);
int ydest = luaL_checkint(L, 4);
int xoffs = luaL_checkint(L, 5);
int yoffs = luaL_checkint(L, 6);
int w = luaL_checkint(L, 7);
int h = luaL_checkint(L, 8);
double p = luaL_checknumber(L, 9);
int x, y;
uint8_t *dstptr;
uint8_t *srcptr;
if(!fitBlitBufferBoundaries(src, dst, &xdest, &ydest, &xoffs, &yoffs, &w, &h))
return 0;
if(xdest & 1) {
/* this will render the leftmost column */
dstptr = (uint8_t*)(dst->data +
ydest * dst->pitch +
xdest / 2);
srcptr = (uint8_t*)(src->data +
yoffs * src->pitch +
xoffs / 2 );
if(xoffs & 1) {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint8_t v = (int)((*dstptr & 0x0F)*(1-p) + (*srcptr & 0x0F)*p);
*dstptr = (*dstptr & 0xF0) | (v < 0x0F ? v : 0x0F);
dstptr += dst->pitch;
srcptr += src->pitch;
}
} else {
for(y = 0; y < h; y++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint8_t v = (int)((*dstptr & 0x0F)*(1-p) + (*srcptr >> 4)*p);
*dstptr = (*dstptr & 0xF0) | (v < 0x0F ? v : 0x0F);
dstptr += dst->pitch;
srcptr += src->pitch;
}
}
xdest++;
xoffs++;
w--;
}
dstptr = (uint8_t*)(dst->data +
ydest * dst->pitch +
xdest / 2);
srcptr = (uint8_t*)(src->data +
yoffs * src->pitch +
xoffs / 2 );
if(xoffs & 1) {
for(y = 0; y < h; y++) {
for(x = 0; x < (w / 2); x++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (int)((dstptr[x] & 0xF0)*(1-p) + ((srcptr[x] & 0x0F) << 4)*p);
uint8_t v2 = (int)((dstptr[x] & 0x0F)*(1-p) + (srcptr[x+1] >> 4)*p);
dstptr[x] = (v1 < 0xF0 ? v1 : 0xF0) | (v2 < 0x0F ? v2 : 0x0F);
}
if(w & 1) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (int)((dstptr[x] & 0xF0)*(1-p) + ((srcptr[x] & 0x0F) << 4)*p);
dstptr[x] = (dstptr[x] & 0x0F) | (v1 < 0xF0 ? v1 : 0xF0);
}
dstptr += dst->pitch;
srcptr += src->pitch;
}
} else {
for(y = 0; y < h; y++) {
for(x = 0; x < (w / 2); x++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (int)((dstptr[x] & 0xF0)*(1-p) + (srcptr[x] & 0xF0)*p);
uint8_t v2 = (int)((dstptr[x] & 0x0F)*(1-p) + (srcptr[x] & 0x0F)*p);
dstptr[x] = (v1 < 0xF0 ? v1 : 0xF0) | (v2 < 0x0F ? v2 : 0x0F);
}
if(w & 1) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
ASSERT_BLITBUFFER_BOUNDARIES(src, srcptr);
uint16_t v1 = (int)((dstptr[x] & 0xF0)*(1-p) + (srcptr[x] & 0xF0)*p);
dstptr[x] = (dstptr[x] & 0x0F) | (v1 < 0xF0 ? v1 : 0xF0);
}
dstptr += dst->pitch;
srcptr += src->pitch;
}
}
return 0;
}
static int paintRect(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3);
int w = luaL_checkint(L, 4);
int h = luaL_checkint(L, 5);
int c = luaL_checkint(L, 6);
uint8_t *dstptr;
int cy;
if(x < 0) {
if (x+w > 0) {
w += x;
x = 0;
} else {
return 0;
}
}
if(y < 0) {
if (y+h > 0) {
h += y;
y = 0;
} else {
return 0;
}
}
if(x + w > dst->w) {
w = dst->w - x;
}
if(y + h > dst->h) {
h = dst->h - y;
}
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
}
if(x & 1) {
/* This will render the leftmost column
* in the case when x is odd. After this,
* x will become even. */
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr &= 0xF0;
*dstptr |= c;
dstptr += dst->pitch;
}
x++;
w--;
}
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
memset(dstptr, c | (c << 4), w / 2);
dstptr += dst->pitch;
}
if(w & 1) {
/* This will render the rightmost column
* in the case when (w & 1) && !(x & 1) or
* !(w & 1) && (x & 1). */
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
(x + w) / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr &= 0x0F;
*dstptr |= (c << 4);
dstptr += dst->pitch;
}
}
return 0;
}
static int invertRect(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3);
int w = luaL_checkint(L, 4);
int h = luaL_checkint(L, 5);
uint8_t *dstptr;
int cy, cx;
//printf("## invertRect x=%d y=%d w=%d h=%d\n",x,y,w,h);
if (x < 0) {
if ( x + w > 0 ) {
w = w + x;
x = 0;
} else {
//printf("## invertRect x out of bound\n");
return 0;
}
}
if (y < 0) {
if ( y + h > 0 ) {
h = h + y;
y = 0;
} else {
//printf("## invertRect y out of bound\n");
return 0;
}
}
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
}
if(x + w > dst->w) {
w = dst->w - x;
}
if(y + h > dst->h) {
h = dst->h - y;
}
if(x & 1) {
/* This will invert the leftmost column
* in the case when x is odd. After this,
* x will become even. */
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr ^= 0x0F;
dstptr += dst->pitch;
}
x++;
w--;
}
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
for(cx = 0; cx < w/2; cx++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, (dstptr+cx));
*(dstptr+cx) ^= 0xFF;
}
dstptr += dst->pitch;
}
if(w & 1) {
/* This will invert the rightmost column
* in the case when (w & 1) && !(x & 1) or
* !(w & 1) && (x & 1). */
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
(x + w) / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
*dstptr ^= 0xF0;
dstptr += dst->pitch;
}
}
return 0;
}
static int dimRect(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3);
int w = luaL_checkint(L, 4);
int h = luaL_checkint(L, 5);
uint8_t *dstptr;
int cy, cx;
if (x < 0) {
if ( x + w > 0 ) {
w = w + x;
x = 0;
} else {
//printf("## invertRect x out of bound\n");
return 0;
}
}
if (y < 0) {
if ( y + h > 0 ) {
h = h + y;
y = 0;
} else {
//printf("## invertRect y out of bound\n");
return 0;
}
}
if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) {
return 0;
}
if(x + w > dst->w) {
w = dst->w - x;
}
if(y + h > dst->h) {
h = dst->h - y;
}
if(x & 1) {
/* This will dimm the leftmost column
* in the case when x is odd. After this,
* x will become even. */
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
int px = *dstptr & 0x0F;
*dstptr &= 0xF0 | px >> 1;
dstptr += dst->pitch;
}
x++;
w--;
}
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
x / 2);
for(cy = 0; cy < h; cy++) {
for(cx = 0; cx < w/2; cx++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, (dstptr+cx));
*(dstptr+cx) =
( *(dstptr+cx) >> 1 ) & 0xF0 |
( *(dstptr+cx) & 0x0F ) >> 1;
}
dstptr += dst->pitch;
}
if(w & 1) {
/* This will dimm the rightmost column
* in the case when (w & 1) && !(x & 1) or
* !(w & 1) && (x & 1). */
dstptr = (uint8_t*)(dst->data +
y * dst->pitch +
(x + w) / 2);
for(cy = 0; cy < h; cy++) {
ASSERT_BLITBUFFER_BOUNDARIES(dst, dstptr);
int px = *dstptr & 0xF0;
*dstptr &= 0x0F | ( px >> 1 & 0xF0 );
dstptr += dst->pitch;
}
}
return 0;
}
/*
* @r: radius
* @c: color of the line to draw
* @w: width of the line to draw
*/
static int paintCircle(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
int center_x = luaL_checkint(L, 2);
int center_y = luaL_checkint(L, 3);
int r = luaL_checkint(L, 4);
int c = luaL_optint(L, 5, 15);
int w = luaL_optint(L, 6, r);
if( (center_x + r > dst->h) || (center_x - r < 0) ||
(center_y + r > dst->w) || (center_y - r < 0) ||
(r == 0)) {
return 0;
}
if(w > r) {
w = r;
}
int tmp_y;
/* for outer circle */
int x = 0, y = r;
float delta = 5/4 - r;
/* for inter circle */
int r2 = r - w;
int x2 = 0, y2 = r2;
float delta2 = 5/4 - r;
/* draw two axles */
for(tmp_y = r; tmp_y > r2; tmp_y--) {
setPixel(dst, center_x+0, center_y+tmp_y, c);
setPixel(dst, center_x-0, center_y-tmp_y, c);
setPixel(dst, center_x+tmp_y, center_y+0, c);
setPixel(dst, center_x-tmp_y, center_y-0, c);
}
while(x < y) {
/* decrease y if we are out of circle */
x++;
if (delta > 0) {
y--;
delta = delta + 2*x - 2*y + 2;
} else {
delta = delta + 2*x + 1;
}
/* inner circle finished drawing, increase y linearly for filling */
if(x2 > y2) {
y2++;
x2++;
} else {
x2++;
if (delta2 > 0) {
y2--;
delta2 = delta2 + 2*x2 - 2*y2 + 2;
} else {
delta2 = delta2 + 2*x2 + 1;
}
}
for(tmp_y = y; tmp_y > y2; tmp_y--) {
setPixel(dst, center_x+x, center_y+tmp_y, c);
setPixel(dst, center_x+tmp_y, center_y+x, c);
setPixel(dst, center_x+tmp_y, center_y-x, c);
setPixel(dst, center_x+x, center_y-tmp_y, c);
setPixel(dst, center_x-x, center_y-tmp_y, c);
setPixel(dst, center_x-tmp_y, center_y-x, c);
setPixel(dst, center_x-tmp_y, center_y+x, c);
setPixel(dst, center_x-x, center_y+tmp_y, c);
}
}
if(r == w) {
setPixel(dst, center_x, center_y, c);
}
return 0;
}
static int paintRoundedCorner(lua_State *L) {
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
int off_x = luaL_checkint(L, 2);
int off_y = luaL_checkint(L, 3);
int w = luaL_checkint(L, 4);
int h = luaL_checkint(L, 5);
int bw = luaL_checkint(L, 6);
int r = luaL_checkint(L, 7);
int c = luaL_optint(L, 8, 15);
if((2*r > h) || (2*r > w) || (r == 0)) {
return 0;
}
if(r > h) {
r = h;
}
if(r > w) {
r = w;
}
if(bw > r) {
bw = r;
}
int tmp_y;
/* for outer circle */
int x = 0, y = r;
float delta = 5/4 - r;
/* for inter circle */
int r2 = r - bw;
int x2 = 0, y2 = r2;
float delta2 = 5/4 - r;
/* draw two axles */
/*for(tmp_y = r; tmp_y > r2; tmp_y--) {*/
/*setPixel(dst, (w-r)+off_x+0, (h-r)+off_y+tmp_y-1, c);*/
/*setPixel(dst, (w-r)+off_x-0, (r)+off_y-tmp_y, c);*/
/*setPixel(dst, (w-r)+off_x+tmp_y, (h-r)+off_y+0, c);*/
/*setPixel(dst, (r)+off_x-tmp_y, (h-r)+off_y-0-1, c);*/
/*}*/
while(x < y) {
/* decrease y if we are out of circle */
x++;
if (delta > 0) {
y--;
delta = delta + 2*x - 2*y + 2;
} else {
delta = delta + 2*x + 1;
}
/* inner circle finished drawing, increase y linearly for filling */
if(x2 > y2) {
y2++;
x2++;
} else {
x2++;
if (delta2 > 0) {
y2--;
delta2 = delta2 + 2*x2 - 2*y2 + 2;
} else {
delta2 = delta2 + 2*x2 + 1;
}
}
for(tmp_y = y; tmp_y > y2; tmp_y--) {
setPixel(dst, (w-r)+off_x+x-1, (h-r)+off_y+tmp_y-1, c);
setPixel(dst, (w-r)+off_x+tmp_y-1, (h-r)+off_y+x-1, c);
setPixel(dst, (w-r)+off_x+tmp_y-1, (r)+off_y-x, c);
setPixel(dst, (w-r)+off_x+x-1, (r)+off_y-tmp_y, c);
setPixel(dst, (r)+off_x-x, (r)+off_y-tmp_y, c);
setPixel(dst, (r)+off_x-tmp_y, (r)+off_y-x, c);
setPixel(dst, (r)+off_x-tmp_y, (h-r)+off_y+x-1, c);
setPixel(dst, (r)+off_x-x, (h-r)+off_y+tmp_y-1, c);
}
}
return 0;
}
static const struct luaL_Reg blitbuffer_func[] = {
{"new", newBlitBuffer},
{NULL, NULL}
};
static const struct luaL_Reg blitbuffer_meth[] = {
{"getWidth", getWidth},
{"getHeight", getHeight},
{"blitFrom", blitToBuffer},
{"blitFromRotate", blitToBufferRotate},
{"addblitFrom", addblitToBuffer},
{"blitFullFrom", blitFullToBuffer},
{"paintRect", paintRect},
{"paintCircle", paintCircle},
{"paintRoundedCorner", paintRoundedCorner},
{"invertRect", invertRect},
{"dimRect", dimRect},
{"free", freeBlitBuffer},
{"__gc", freeBlitBuffer},
{NULL, NULL}
};
int luaopen_blitbuffer(lua_State *L) {
luaL_newmetatable(L, "blitbuffer");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, blitbuffer_meth);
lua_setglobal(L, "blitbuffer");
luaL_register(L, "Blitbuffer", blitbuffer_func);
return 1;
}

@ -1,37 +0,0 @@
/*
KindlePDFViewer: buffer for blitting muPDF data to framebuffer (blitbuffer)
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BLITBUFFER_H
#define _BLITBUFFER_H
#include <stdint.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
typedef struct BlitBuffer {
int w;
int h;
int pitch;
uint8_t *data;
uint8_t allocated;
} BlitBuffer;
int newBlitBufferNative(lua_State *L, int w, int h, int pitch, BlitBuffer **newBuffer);
int luaopen_blitbuffer(lua_State *L);
#endif

@ -1,723 +0,0 @@
/*
KindlePDFViewer: CREngine abstraction for Lua
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
Qingping Hou <qingping.hou@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEBUG_CRENGINE
#define DEBUG_CRENGINE 0
#endif
extern "C" {
#include "blitbuffer.h"
#include "drawcontext.h"
#include "cre.h"
}
#include "crengine.h"
typedef struct CreDocument {
LVDocView *text_view;
ldomDocument *dom_doc;
} CreDocument;
static int initCache(lua_State *L) {
int cache_size = luaL_optint(L, 1, (2 << 20) * 64); // 64Mb on disk cache for DOM
ldomDocCache::init(lString16("./cr3cache"), cache_size);
HyphMan::initDictionaries(lString16("data/hyph/"));
return 0;
}
static int newDocView(lua_State *L) {
int width = luaL_checkint(L, 1);
int height = luaL_checkint(L, 2);
LVDocViewMode view_mode = (LVDocViewMode)luaL_checkint(L, 3);
CreDocument *doc = (CreDocument*) lua_newuserdata(L, sizeof(CreDocument));
luaL_getmetatable(L, "credocument");
lua_setmetatable(L, -2);
doc->text_view = new LVDocView();
//doc->text_view->setBackgroundColor(0xFFFFFF);
//doc->text_view->setTextColor(0x000000);
//doc->text_view->doCommand(DCMD_SET_DOC_FONTS, 1);
//doc->text_view->doCommand(DCMD_SET_INTERNAL_STYLES, 1);
doc->text_view->setViewMode(view_mode, -1);
doc->text_view->Resize(width, height);
doc->text_view->setPageHeaderInfo(PGHDR_AUTHOR|PGHDR_TITLE|PGHDR_PAGE_NUMBER|PGHDR_PAGE_COUNT|PGHDR_CHAPTER_MARKS|PGHDR_CLOCK);
return 1;
}
static int getGammaIndex(lua_State *L) {
lua_pushinteger(L, fontMan->GetGammaIndex());
return 1;
}
static int setGammaIndex(lua_State *L) {
int index = luaL_checkint(L, 1);
fontMan->SetGammaIndex(index);
return 0;
}
static int loadDocument(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *file_name = luaL_checkstring(L, 2);
doc->text_view->LoadDocument(file_name);
doc->dom_doc = doc->text_view->getDocument();
doc->text_view->Render();
return 0;
}
static int closeDocument(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
/* should be save if called twice */
if(doc->text_view != NULL) {
delete doc->text_view;
doc->text_view = NULL;
}
return 0;
}
static int getNumberOfPages(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getPageCount());
return 1;
}
static int getCurrentPage(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getCurPage()+1);
return 1;
}
static int getPageFromXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *xpointer_str = luaL_checkstring(L, 2);
int page = 1;
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
page = doc->text_view->getBookmarkPage(xp) + 1;
lua_pushinteger(L, page);
return 1;
}
static int getPosFromXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *xpointer_str = luaL_checkstring(L, 2);
int pos = 0;
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
lvPoint pt = xp.toPoint();
if (pt.y > 0) {
pos = pt.y;
}
lua_pushinteger(L, pos);
return 1;
}
static int getCurrentPos(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->GetPos());
return 1;
}
static int getCurrentPercent(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getPosPercent());
return 1;
}
static int getXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
ldomXPointer xp = doc->text_view->getBookmark();
lua_pushstring(L, UnicodeToLocal(xp.toString()).c_str());
return 1;
}
static int getFullHeight(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->GetFullHeight());
return 1;
}
static int getFontSize(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getFontSize());
return 1;
}
static int getFontFace(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushstring(L, doc->text_view->getDefaultFontFace().c_str());
return 1;
}
/*
* helper function for getTableOfContent()
*/
static int walkTableOfContent(lua_State *L, LVTocItem *toc, int *count) {
LVTocItem *toc_tmp = NULL;
int i = 0,
nr_child = toc->getChildCount();
for (i = 0; i < nr_child; i++) {
toc_tmp = toc->getChild(i);
lua_pushnumber(L, (*count)++);
/* set subtable, Toc entry */
lua_newtable(L);
lua_pushstring(L, "page");
lua_pushnumber(L, toc_tmp->getPage()+1);
lua_settable(L, -3);
lua_pushstring(L, "xpointer");
lua_pushstring(L, UnicodeToLocal(
toc_tmp->getXPointer().toString()).c_str()
);
lua_settable(L, -3);
lua_pushstring(L, "depth");
lua_pushnumber(L, toc_tmp->getLevel());
lua_settable(L, -3);
lua_pushstring(L, "title");
lua_pushstring(L, UnicodeToLocal(toc_tmp->getName()).c_str());
lua_settable(L, -3);
/* set Toc entry to Toc table */
lua_settable(L, -3);
if (toc_tmp->getChildCount() > 0) {
walkTableOfContent(L, toc_tmp, count);
}
}
return 0;
}
/*
* Return a table like this:
* {
* {
* page=12,
* xpointer = "/body/DocFragment[11].0",
* depth=1,
* title="chapter1"
* },
* {
* page=54,
* xpointer = "/body/DocFragment[13].0",
* depth=1,
* title="chapter2"
* },
* }
*
*/
static int getTableOfContent(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
LVTocItem * toc = doc->text_view->getToc();
int count = 1;
lua_newtable(L);
walkTableOfContent(L, toc, &count);
return 1;
}
/*
* Return a table like this:
* {
* "FreeMono",
* "FreeSans",
* "FreeSerif",
* }
*
*/
static int getFontFaces(lua_State *L) {
int i = 0;
lString16Collection face_list;
fontMan->getFaceList(face_list);
lua_newtable(L);
for (i = 0; i < face_list.length(); i++)
{
lua_pushnumber(L, i+1);
lua_pushstring(L, UnicodeToLocal(face_list[i]).c_str());
lua_settable(L, -3);
}
return 1;
}
static int setViewMode(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
LVDocViewMode view_mode = (LVDocViewMode)luaL_checkint(L, 2);
doc->text_view->setViewMode(view_mode, -1);
return 0;
}
static int setHeaderInfo(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int info = luaL_checkint(L, 2);
doc->text_view->setPageHeaderInfo(info);
return 0;
}
static int setHeaderFont(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *face = luaL_checkstring(L, 2);
doc->text_view->setStatusFontFace(lString8(face));
return 0;
}
static int setFontFace(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *face = luaL_checkstring(L, 2);
doc->text_view->setDefaultFontFace(lString8(face));
//fontMan->SetFallbackFontFace(lString8(face));
return 0;
}
static int gotoPage(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int pageno = luaL_checkint(L, 2);
doc->text_view->goToPage(pageno-1);
return 0;
}
static int gotoPercent(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int percent = luaL_checkint(L, 2);
doc->text_view->SetPos(percent * doc->text_view->GetFullHeight() / 10000);
return 0;
}
static int gotoPos(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int pos = luaL_checkint(L, 2);
doc->text_view->SetPos(pos);
return 0;
}
static int gotoXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *xpointer_str = luaL_checkstring(L, 2);
ldomXPointer xp = doc->dom_doc->createXPointer(lString16(xpointer_str));
doc->text_view->goToBookmark(xp);
/* CREngine does not call checkPos() immediately after goToBookmark,
* so I have to manually update the pos in order to get a correct
* return from GetPos() call. */
doc->text_view->SetPos(xp.toPoint().y);
return 0;
}
/* zoom font by given delta and return zoomed font size */
static int zoomFont(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int delta = luaL_checkint(L, 2);
doc->text_view->ZoomFont(delta);
lua_pushnumber(L, doc->text_view->getFontSize());
return 1;
}
static int setFontSize(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int size = luaL_checkint(L, 2);
doc->text_view->setFontSize(size);
return 0;
}
static int setDefaultInterlineSpace(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
int space = luaL_checkint(L, 2);
doc->text_view->setDefaultInterlineSpace(space);
return 0;
}
static int setStyleSheet(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char* style_sheet = luaL_checkstring(L, 2);
lString8 css;
if (LVLoadStylesheetFile(lString16(style_sheet), css)){
doc->text_view->setStyleSheet(css);
} else {
doc->text_view->setStyleSheet(lString8());
}
return 0;
}
static int setEmbeddedStyleSheet(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
doc->text_view->doCommand(DCMD_SET_INTERNAL_STYLES, luaL_checkint(L, 2));
return 0;
}
static int toggleFontBolder(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
doc->text_view->doCommand(DCMD_TOGGLE_BOLD);
return 0;
}
static int cursorRight(lua_State *L) {
//CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
//LVDocView *tv = doc->text_view;
//ldomXPointer p = tv->getCurrentPageMiddleParagraph();
//lString16 s = p.getText();
//lString16 s = p.toString();
//printf("~~~~~~~~~~%s\n", UnicodeToLocal(s).c_str());
//tv->selectRange(*(tv->selectFirstPageLink()));
//ldomXRange *r = tv->selectNextPageLink(true);
//lString16 s = r->getRangeText();
//printf("------%s\n", UnicodeToLocal(s).c_str());
//tv->selectRange(*r);
//tv->updateSelections();
//LVPageWordSelector sel(doc->text_view);
//doc->text_view->doCommand(DCMD_SELECT_FIRST_SENTENCE);
//sel.moveBy(DIR_RIGHT, 2);
//printf("---------------- %s\n", UnicodeToLocal(sel.getSelectedWord()->getText()).c_str());
return 0;
}
static int getPageLinks(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_newtable(L); // all links
ldomXRangeList links;
ldomXRangeList & sel = doc->text_view->getDocument()->getSelections();
doc->text_view->getCurrentPageLinks( links );
int linkCount = links.length();
if ( linkCount ) {
sel.clear();
for ( int i=0; i<linkCount; i++ ) {
lString16 txt = links[i]->getRangeText();
lString8 txt8 = UnicodeToLocal( txt );
lString16 link = links[i]->getHRef();
lString8 link8 = UnicodeToLocal( link );
ldomXRange currSel;
currSel = *links[i];
lvPoint start_pt ( currSel.getStart().toPoint() );
lvPoint end_pt ( currSel.getEnd().toPoint() );
CRLog::debug("# link %d start %d %d end %d %d '%s' %s\n", i,
start_pt.x, start_pt.y, end_pt.x, end_pt.y,
txt8.c_str(), link8.c_str()
);
lua_newtable(L); // new link
lua_pushstring(L, "start_x");
lua_pushinteger(L, start_pt.x);
lua_settable(L, -3);
lua_pushstring(L, "start_y");
lua_pushinteger(L, start_pt.y);
lua_settable(L, -3);
lua_pushstring(L, "end_x");
lua_pushinteger(L, end_pt.x);
lua_settable(L, -3);
lua_pushstring(L, "end_y");
lua_pushinteger(L, end_pt.y);
lua_settable(L, -3);
const char * link_to = link8.c_str();
if ( link_to[0] == '#' ) {
lua_pushstring(L, "section");
lua_pushstring(L, link_to);
lua_settable(L, -3);
sel.add( new ldomXRange(*links[i]) ); // highlight
} else {
lua_pushstring(L, "uri");
lua_pushstring(L, link_to);
lua_settable(L, -3);
}
lua_rawseti(L, -2, i + 1);
}
doc->text_view->updateSelections();
}
return 1;
}
static int gotoLink(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *pos = luaL_checkstring(L, 2);
doc->text_view->goLink(lString16(pos), true);
return 0;
}
static int clearSelection(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
doc->text_view->clearSelection();
return 0;
}
static int drawCurrentPage(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
int w = bb->w,
h = bb->h;
/* Set DrawBuf to 4bpp */
LVGrayDrawBuf drawBuf(w, h, 4);
doc->text_view->Resize(w, h);
doc->text_view->Render();
doc->text_view->Draw(drawBuf);
uint8_t *bbptr = (uint8_t*)bb->data;
uint8_t *pmptr = (uint8_t*)drawBuf.GetScanLine(0);
int i,x;
for (i = 0; i < h; i++) {
for (x = 0; x < (bb->w / 2); x++) {
/* When DrawBuf is set to 4bpp mode, CREngine still put every
* four bits in one byte, but left the last 4 bits zero*/
bbptr[x] = ~(pmptr[x*2] | (pmptr[x*2+1] >> 4));
}
if(bb->w & 1) {
bbptr[x] = 255 - (pmptr[x*2] & 0xF0);
}
bbptr += bb->pitch;
pmptr += w;
}
return 0;
}
static int registerFont(lua_State *L) {
const char *fontfile = luaL_checkstring(L, 1);
if ( !fontMan->RegisterFont(lString8(fontfile)) ) {
return luaL_error(L, "cannot register font <%s>", fontfile);
}
return 0;
}
// ported from Android UI kpvcrlib/crengine/android/jni/docview.cpp
static int findText(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
const char *l_pattern = luaL_checkstring(L, 2);
lString16 pattern = lString16(l_pattern);
int origin = luaL_checkint(L, 3);
bool reverse = luaL_checkint(L, 4);
bool caseInsensitive = luaL_checkint(L, 5);
if ( pattern.empty() )
return 0;
LVArray<ldomWord> words;
lvRect rc;
doc->text_view->GetPos( rc );
int pageHeight = rc.height();
int start = -1;
int end = -1;
if ( reverse ) {
// reverse
if ( origin == 0 ) {
// from end current page to first page
end = rc.bottom;
} else if ( origin == -1 ) {
// from last page to end of current page
start = rc.bottom;
} else { // origin == 1
// from prev page to first page
end = rc.top;
}
} else {
// forward
if ( origin == 0 ) {
// from current page to last page
start = rc.top;
} else if ( origin == -1 ) {
// from first page to current page
end = rc.top;
} else { // origin == 1
// from next page to last
start = rc.bottom;
}
}
CRLog::debug("CRViewDialog::findText: Current page: %d .. %d", rc.top, rc.bottom);
CRLog::debug("CRViewDialog::findText: searching for text '%s' from %d to %d origin %d", LCSTR(pattern), start, end, origin );
if ( doc->text_view->getDocument()->findText( pattern, caseInsensitive, reverse, start, end, words, 200, pageHeight ) ) {
CRLog::debug("CRViewDialog::findText: pattern found");
doc->text_view->clearSelection();
doc->text_view->selectWords( words );
ldomMarkedRangeList * ranges = doc->text_view->getMarkedRanges();
if ( ranges ) {
if ( ranges->length()>0 ) {
int pos = ranges->get(0)->start.y;
//doc->text_view->SetPos(pos); // commented out not to mask lua code which does the same
CRLog::debug("# SetPos = %d", pos);
lua_pushinteger(L, ranges->length()); // results found
lua_pushinteger(L, pos);
return 2;
}
}
return 0;
}
CRLog::debug("CRViewDialog::findText: pattern not found");
return 0;
}
static const struct luaL_Reg cre_func[] = {
{"initCache", initCache},
{"newDocView", newDocView},
{"getFontFaces", getFontFaces},
{"getGammaIndex", getGammaIndex},
{"setGammaIndex", setGammaIndex},
{"registerFont", registerFont},
{NULL, NULL}
};
static const struct luaL_Reg credocument_meth[] = {
{"loadDocument", loadDocument},
/*--- get methods ---*/
{"getPages", getNumberOfPages},
{"getCurrentPage", getCurrentPage},
{"getPageFromXPointer", getPageFromXPointer},
{"getPosFromXPointer", getPosFromXPointer},
{"getCurrentPos", getCurrentPos},
{"getCurrentPercent", getCurrentPercent},
{"getXPointer", getXPointer},
{"getFullHeight", getFullHeight},
{"getFontSize", getFontSize},
{"getFontFace", getFontFace},
{"getToc", getTableOfContent},
/*--- set methods ---*/
{"setViewMode", setViewMode},
{"setHeaderInfo", setHeaderInfo},
{"setHeaderFont", setHeaderFont},
{"setFontFace", setFontFace},
{"setFontSize", setFontSize},
{"setDefaultInterlineSpace", setDefaultInterlineSpace},
{"setStyleSheet", setStyleSheet},
{"setEmbeddedStyleSheet", setEmbeddedStyleSheet},
/* --- control methods ---*/
{"gotoPage", gotoPage},
{"gotoPercent", gotoPercent},
{"gotoPos", gotoPos},
{"gotoXPointer", gotoXPointer},
{"zoomFont", zoomFont},
{"toggleFontBolder", toggleFontBolder},
//{"cursorLeft", cursorLeft},
//{"cursorRight", cursorRight},
{"drawCurrentPage", drawCurrentPage},
{"findText", findText},
{"getPageLinks", getPageLinks},
{"gotoLink", gotoLink},
{"clearSelection", clearSelection},
{"close", closeDocument},
{"__gc", closeDocument},
{NULL, NULL}
};
int luaopen_cre(lua_State *L) {
luaL_newmetatable(L, "credocument");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, credocument_meth);
lua_pop(L, 1);
luaL_register(L, "cre", cre_func);
/* initialize font manager for CREngine */
InitFontManager(lString8());
#if DEBUG_CRENGINE
CRLog::setStdoutLogger();
CRLog::setLogLevel(CRLog::LL_DEBUG);
#endif
return 1;
}

28
cre.h

@ -1,28 +0,0 @@
/*
KindlePDFViewer: CREngine abstraction for Lua
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
Qingping Hou <qingping.hou@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CRENGING_H
#define _CRENGING_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_cre(lua_State *L);
#endif

722
djvu.c

@ -1,722 +0,0 @@
/*
KindlePDFViewer: DjvuLibre abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <libdjvu/miniexp.h>
#include <libdjvu/ddjvuapi.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "koptcontext.h"
#include "k2pdfopt.h"
#include "djvu.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
typedef struct DjvuDocument {
ddjvu_context_t *context;
ddjvu_document_t *doc_ref;
ddjvu_format_t *pixelformat;
} DjvuDocument;
typedef struct DjvuPage {
int num;
ddjvu_page_t *page_ref;
ddjvu_pageinfo_t info;
DjvuDocument *doc;
} DjvuPage;
static int handle(lua_State *L, ddjvu_context_t *ctx, int wait)
{
const ddjvu_message_t *msg;
if (!ctx)
return -1;
if (wait)
msg = ddjvu_message_wait(ctx);
while ((msg = ddjvu_message_peek(ctx)))
{
switch(msg->m_any.tag)
{
case DDJVU_ERROR:
if (msg->m_error.filename) {
return luaL_error(L, "ddjvu: %s\nddjvu: '%s:%d'\n",
msg->m_error.message, msg->m_error.filename,
msg->m_error.lineno);
} else {
return luaL_error(L, "ddjvu: %s\n", msg->m_error.message);
}
default:
break;
}
ddjvu_message_pop(ctx);
}
return 0;
}
static int openDocument(lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
int cache_size = luaL_optint(L, 2, 10 << 20);
DjvuDocument *doc = (DjvuDocument*) lua_newuserdata(L, sizeof(DjvuDocument));
luaL_getmetatable(L, "djvudocument");
lua_setmetatable(L, -2);
doc->context = ddjvu_context_create("kindlepdfviewer");
if (! doc->context) {
return luaL_error(L, "cannot create context");
}
//printf("## cache_size = %d\n", cache_size);
ddjvu_cache_set_size(doc->context, (unsigned long)cache_size);
doc->doc_ref = ddjvu_document_create_by_filename_utf8(doc->context, filename, TRUE);
if (! doc->doc_ref)
return luaL_error(L, "cannot open DjVu file <%s>", filename);
while (! ddjvu_document_decoding_done(doc->doc_ref))
handle(L, doc->context, True);
doc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL);
if (! doc->pixelformat) {
return luaL_error(L, "cannot create DjVu pixelformat for <%s>", filename);
}
ddjvu_format_set_row_order(doc->pixelformat, 1);
ddjvu_format_set_y_direction(doc->pixelformat, 1);
/* dithering bits <8 are ignored by djvulibre */
/* ddjvu_format_set_ditherbits(doc->pixelformat, 4); */
return 1;
}
static int closeDocument(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
// should be safe if called twice
if (doc->doc_ref != NULL) {
ddjvu_document_release(doc->doc_ref);
doc->doc_ref = NULL;
}
if (doc->context != NULL) {
ddjvu_context_release(doc->context);
doc->context = NULL;
}
if (doc->pixelformat != NULL) {
ddjvu_format_release(doc->pixelformat);
doc->pixelformat = NULL;
}
return 0;
}
static int getNumberOfPages(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
lua_pushinteger(L, ddjvu_document_get_pagenum(doc->doc_ref));
return 1;
}
static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) {
depth++;
miniexp_t lista = miniexp_cdr(r); // go inside bookmars in the list
int length = miniexp_length(r);
int counter = 0;
const char* page_name;
int page_number;
while(counter < length-1) {
lua_pushnumber(L, *count);
lua_newtable(L);
lua_pushstring(L, "page");
page_name = miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))));
if(page_name != NULL && page_name[0] == '#') {
errno = 0;
page_number = strtol(page_name + 1, NULL, 10);
if(!errno) {
lua_pushnumber(L, page_number);
} else {
/* we can not parse this as a number, TODO: parse page names */
lua_pushnumber(L, -1);
}
} else {
/* something we did not expect here */
lua_pushnumber(L, -1);
}
lua_settable(L, -3);
lua_pushstring(L, "depth");
lua_pushnumber(L, depth);
lua_settable(L, -3);
lua_pushstring(L, "title");
lua_pushstring(L, miniexp_to_str(miniexp_car(miniexp_nth(counter, lista))));
lua_settable(L, -3);
lua_settable(L, -3);
(*count)++;
if (miniexp_length(miniexp_cdr(miniexp_nth(counter, lista))) > 1) {
walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter, lista)), count, depth);
}
counter++;
}
return 0;
}
static int getTableOfContent(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
miniexp_t r;
int count = 1;
while ((r=ddjvu_document_get_outline(doc->doc_ref))==miniexp_dummy)
handle(L, doc->context, True);
//printf("lista: %s\n", miniexp_to_str(miniexp_car(miniexp_nth(1, miniexp_cdr(r)))));
lua_newtable(L);
walkTableOfContent(L, r, &count, 0);
return 1;
}
static int openPage(lua_State *L) {
ddjvu_status_t r;
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
if (pageno < 1 || pageno > ddjvu_document_get_pagenum(doc->doc_ref)) {
return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, ddjvu_document_get_pagenum(doc->doc_ref));
}
DjvuPage *page = (DjvuPage*) lua_newuserdata(L, sizeof(DjvuPage));
luaL_getmetatable(L, "djvupage");
lua_setmetatable(L, -2);
/* djvulibre counts page starts from 0 */
page->page_ref = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1);
if (! page->page_ref)
return luaL_error(L, "cannot open page #%d", pageno);
while (! ddjvu_page_decoding_done(page->page_ref))
handle(L, doc->context, TRUE);
page->doc = doc;
page->num = pageno;
/* djvulibre counts page starts from 0 */
while((r=ddjvu_document_get_pageinfo(doc->doc_ref, pageno - 1,
&(page->info)))<DDJVU_JOB_OK)
handle(L, doc->context, TRUE);
if (r>=DDJVU_JOB_FAILED)
return luaL_error(L, "cannot get page #%d information", pageno);
return 1;
}
/* get page size after zoomed */
static int getPageSize(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
lua_pushnumber(L, dc->zoom * page->info.width);
lua_pushnumber(L, dc->zoom * page->info.height);
return 2;
}
/* unsupported so fake it */
static int getUsedBBox(lua_State *L) {
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)-0.01);
lua_pushnumber(L, (double)-0.01);
return 4;
}
static int getOriginalPageSize(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
ddjvu_status_t r;
ddjvu_pageinfo_t info;
while ((r=ddjvu_document_get_pageinfo(
doc->doc_ref, pageno-1, &info))<DDJVU_JOB_OK) {
handle(L, doc->context, TRUE);
}
lua_pushnumber(L, info.width);
lua_pushnumber(L, info.height);
return 2;
}
static int getPageInfo(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
ddjvu_page_t *djvu_page;
int page_width, page_height, page_dpi;
double page_gamma;
ddjvu_page_type_t page_type;
char *page_type_str;
djvu_page = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1);
if (! djvu_page)
return luaL_error(L, "cannot create djvu_page #%d", pageno);
while (! ddjvu_page_decoding_done(djvu_page))
handle(L, doc->context, TRUE);
page_width = ddjvu_page_get_width(djvu_page);
lua_pushnumber(L, page_width);
page_height = ddjvu_page_get_height(djvu_page);
lua_pushnumber(L, page_height);
page_dpi = ddjvu_page_get_resolution(djvu_page);
lua_pushnumber(L, page_dpi);
page_gamma = ddjvu_page_get_gamma(djvu_page);
lua_pushnumber(L, page_gamma);
page_type = ddjvu_page_get_type(djvu_page);
switch (page_type) {
case DDJVU_PAGETYPE_UNKNOWN:
page_type_str = "UNKNOWN";
break;
case DDJVU_PAGETYPE_BITONAL:
page_type_str = "BITONAL";
break;
case DDJVU_PAGETYPE_PHOTO:
page_type_str = "PHOTO";
break;
case DDJVU_PAGETYPE_COMPOUND:
page_type_str = "COMPOUND";
break;
default:
page_type_str = "INVALID";
break;
}
lua_pushstring(L, page_type_str);
ddjvu_page_release(djvu_page);
return 5;
}
/*
* Return a table like following:
* {
* -- a line entry
* 1 = {
* 1 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 2 = {word="is", x0=377, y0=4857, x1=2427, y1=5089},
* 3 = {word="Word", x0=377, y0=4857, x1=2427, y1=5089},
* 4 = {word="List", x0=377, y0=4857, x1=2427, y1=5089},
* x0 = 377, y0 = 4857, x1 = 2427, y1 = 5089,
* },
*
* -- an other line entry
* 2 = {
* 1 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 2 = {word="is", x0=377, y0=4857, x1=2427, y1=5089},
* x0 = 377, y0 = 4857, x1 = 2427, y1 = 5089,
* },
* }
*/
static int getPageText(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2);
/* get page height for coordinates transform */
ddjvu_pageinfo_t info;
ddjvu_status_t r;
while ((r=ddjvu_document_get_pageinfo(
doc->doc_ref, pageno-1, &info))<DDJVU_JOB_OK) {
handle(L, doc->context, TRUE);
}
if (r>=DDJVU_JOB_FAILED)
return luaL_error(L, "cannot get page #%d information", pageno);
/* start retrieving page text */
miniexp_t sexp, se_line, se_word;
int i = 1, j = 1, counter_l = 1, counter_w=1,
nr_line = 0, nr_word = 0;
const char *word = NULL;
while ((sexp = ddjvu_document_get_pagetext(doc->doc_ref, pageno-1, "word"))
== miniexp_dummy) {
handle(L, doc->context, True);
}
/* throuw page info and obtain lines info, after this, sexp's entries
* are lines. */
sexp = miniexp_cdr(sexp);
/* get number of lines in a page */
nr_line = miniexp_length(sexp);
/* table that contains all the lines */
lua_newtable(L);
counter_l = 1;
for(i = 1; i <= nr_line; i++) {
/* retrive one line entry */
se_line = miniexp_nth(i, sexp);
nr_word = miniexp_length(se_line);
if (nr_word == 0) {
continue;
}
/* subtable that contains words in a line */
lua_pushnumber(L, counter_l);
lua_newtable(L);
counter_l++;
/* set line position */
lua_pushstring(L, "x0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(1, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(2, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(3, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(4, se_line)));
lua_settable(L, -3);
/* now loop through each word in the line */
counter_w = 1;
for(j = 1; j <= nr_word; j++) {
/* retrive one word entry */
se_word = miniexp_nth(j, se_line);
/* check to see whether the entry is empty */
word = miniexp_to_str(miniexp_nth(5, se_word));
if (!word) {
continue;
}
/* create table that contains info for a word */
lua_pushnumber(L, counter_w);
lua_newtable(L);
counter_w++;
/* set word info */
lua_pushstring(L, "x0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(1, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(2, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(3, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushnumber(L,
info.height - miniexp_to_int(miniexp_nth(4, se_word)));
lua_settable(L, -3);
lua_pushstring(L, "word");
lua_pushstring(L, word);
lua_settable(L, -3);
/* set word entry to line subtable */
lua_settable(L, -3);
} /* end of for (j) */
/* set line entry to page text table */
lua_settable(L, -3);
} /* end of for (i) */
return 1;
}
static int closePage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
// should be safe if called twice
if (page->page_ref != NULL) {
ddjvu_page_release(page->page_ref);
page->page_ref = NULL;
}
return 0;
}
static int reflowPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
KOPTContext *kctx = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
ddjvu_render_mode_t mode = (int) luaL_checkint(L, 3);
ddjvu_rect_t prect;
ddjvu_rect_t rrect;
int px, py, pw, ph, rx, ry, rw, rh, idpi, status;
double zoom = kctx->zoom;
double dpi = 250*zoom;
px = 0;
py = 0;
pw = ddjvu_page_get_width(page->page_ref);
ph = ddjvu_page_get_height(page->page_ref);
idpi = ddjvu_page_get_resolution(page->page_ref);
prect.x = px;
prect.y = py;
rx = (int)kctx->bbox.x0;
ry = (int)kctx->bbox.y0;
rw = (int)(kctx->bbox.x1 - kctx->bbox.x0);
rh = (int)(kctx->bbox.y1 - kctx->bbox.y0);
do {
prect.w = pw * dpi / idpi;
prect.h = ph * dpi / idpi;
rrect.x = rx * dpi / idpi;
rrect.y = ry * dpi / idpi;
rrect.w = rw * dpi / idpi;
rrect.h = rh * dpi / idpi;
printf("rendering page:%d,%d,%d,%d dpi:%.0f idpi:%.0d\n",rrect.x,rrect.y,rrect.w,rrect.h,dpi,idpi);
kctx->zoom = zoom;
zoom *= kctx->shrink_factor;
dpi *= kctx->shrink_factor;
} while (rrect.w > kctx->read_max_width | rrect.h > kctx->read_max_height);
WILLUSBITMAP *src = malloc(sizeof(WILLUSBITMAP));
bmp_init(src);
src->width = rrect.w;
src->height = rrect.h;
src->bpp = 8;
bmp_alloc(src);
if (src->bpp == 8) {
int ii;
for (ii = 0; ii < 256; ii++)
src->red[ii] = src->blue[ii] = src->green[ii] = ii;
}
ddjvu_format_set_row_order(page->doc->pixelformat, 1);
status = ddjvu_page_render(page->page_ref, mode, &prect, &rrect, page->doc->pixelformat,
bmp_bytewidth(src), (char *) src->data);
kctx->src = src;
if (kctx->precache) {
pthread_t rf_thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&rf_thread, &attr, k2pdfopt_reflow_bmp, (void*) kctx);
pthread_attr_destroy(&attr);
} else {
k2pdfopt_reflow_bmp(kctx);
}
return 0;
}
static int drawReflowedPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
uint8_t *koptr = kc->data;
uint8_t *bbptr = bb->data;
int x_offset = 0;
int y_offset = 0;
bbptr += bb->pitch * y_offset;
int x, y;
for(y = y_offset; y < bb->h; y++) {
for(x = x_offset/2; x < (bb->w/2); x++) {
int p = x*2 - x_offset;
bbptr[x] = (((koptr[p + 1] & 0xF0) >> 4) | (koptr[p] & 0xF0)) ^ 0xFF;
}
bbptr += bb->pitch;
koptr += bb->w;
if (bb->w & 1) {
bbptr[x] = 255 - (koptr[x*2] & 0xF0);
}
}
return 0;
}
static int drawPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
ddjvu_render_mode_t djvu_render_mode = (int) luaL_checkint(L, 6);
unsigned char adjusted_low[16], adjusted_high[16];
int i, adjust_pixels = 0;
ddjvu_rect_t pagerect, renderrect;
int bbsize = (bb->w)*(bb->h)+1;
uint8_t *imagebuffer = malloc(bbsize);
/*printf("@page %d, @@zoom:%f, offset: (%d, %d)\n", page->num, dc->zoom, dc->offset_x, dc->offset_y);*/
/* render full page into rectangle specified by pagerect */
pagerect.x = 0;
pagerect.y = 0;
pagerect.w = page->info.width * dc->zoom;
pagerect.h = page->info.height * dc->zoom;
/*printf("--pagerect--- (x: %d, y: %d), w: %d, h: %d.\n", 0, 0, pagerect.w, pagerect.h);*/
/* copy pixels area from pagerect specified by renderrect.
*
* ddjvulibre library does not support negative offset, positive offset
* means moving towards right and down.
*
* However, djvureader.lua handles offset differently. It uses negative
* offset to move right and down while positive offset to move left
* and up. So we need to handle positive offset manually when copying
* imagebuffer to blitbuffer (framebuffer).
*/
renderrect.x = MAX(-dc->offset_x, 0);
renderrect.y = MAX(-dc->offset_y, 0);
renderrect.w = MIN(pagerect.w - renderrect.x, bb->w);
renderrect.h = MIN(pagerect.h - renderrect.y, bb->h);
/*printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h);*/
/* ddjvulibre library only supports rotation of 0, 90, 180 and 270 degrees.
* These four kinds of rotations can already be achieved by native system.
* So we don't set rotation here.
*/
if (!ddjvu_page_render(page->page_ref, djvu_render_mode, &pagerect, &renderrect, page->doc->pixelformat, bb->w, imagebuffer))
memset(imagebuffer, 0xFF, bbsize);
uint8_t *bbptr = bb->data;
uint8_t *pmptr = imagebuffer;
int x, y;
/* if offset is positive, we are moving towards up and left. */
int x_offset = MAX(0, dc->offset_x);
int y_offset = MAX(0, dc->offset_y);
/* prepare the tables for adjusting the intensity of pixels */
if (dc->gamma != -1.0) {
for (i=0; i<16; i++) {
adjusted_low[i] = MIN(15, (unsigned char)floorf(dc->gamma * (float)i));
adjusted_high[i] = adjusted_low[i] << 4;
}
adjust_pixels = 1;
}
bbptr += bb->pitch * y_offset;
for(y = y_offset; y < bb->h; y++) {
/* bbptr's line width is half of pmptr's */
for(x = x_offset/2; x < (bb->w / 2); x++) {
int p = x*2 - x_offset;
unsigned char low = 15 - (pmptr[p + 1] >> 4);
unsigned char high = 15 - (pmptr[p] >> 4);
if (adjust_pixels)
bbptr[x] = adjusted_high[high] | adjusted_low[low];
else
bbptr[x] = (high << 4) | low;
}
if (bb->w & 1) {
bbptr[x] = 255 - (pmptr[x*2] & 0xF0);
}
/* go to next line */
bbptr += bb->pitch;
pmptr += bb->w;
}
free(imagebuffer);
return 0;
}
static int getCacheSize(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
unsigned long size = ddjvu_cache_get_size(doc->context);
//printf("## ddjvu_cache_get_size = %d\n", (int)size);
lua_pushnumber(L, size);
return 1;
}
static int cleanCache(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
//printf("## ddjvu_cache_clear\n");
ddjvu_cache_clear(doc->context);
return 0;
}
static const struct luaL_Reg djvu_func[] = {
{"openDocument", openDocument},
{NULL, NULL}
};
static const struct luaL_Reg djvudocument_meth[] = {
{"openPage", openPage},
{"getPages", getNumberOfPages},
{"getToc", getTableOfContent},
{"getPageText", getPageText},
{"getOriginalPageSize", getOriginalPageSize},
{"getPageInfo", getPageInfo},
{"close", closeDocument},
{"getCacheSize", getCacheSize},
{"cleanCache", cleanCache},
{"__gc", closeDocument},
{NULL, NULL}
};
static const struct luaL_Reg djvupage_meth[] = {
{"getSize", getPageSize},
{"getUsedBBox", getUsedBBox},
{"close", closePage},
{"__gc", closePage},
{"reflow", reflowPage},
{"rfdraw", drawReflowedPage},
{"draw", drawPage},
{NULL, NULL}
};
int luaopen_djvu(lua_State *L) {
luaL_newmetatable(L, "djvudocument");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, djvudocument_meth);
lua_pop(L, 1);
luaL_newmetatable(L, "djvupage");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, djvupage_meth);
lua_pop(L, 1);
luaL_register(L, "djvu", djvu_func);
return 1;
}

@ -1,28 +0,0 @@
/*
KindlePDFViewer: DjvuLibre abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DJVU_H
#define _DJVU_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_djvu(lua_State *L);
#define True 1
#endif

@ -1 +0,0 @@
Subproject commit 01a26bed05c8f5ed36e015d16cc54e52dddcccb7

@ -1,117 +0,0 @@
/*
KindlePDFViewer: a DC abstraction
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "drawcontext.h"
static int newDrawContext(lua_State *L) {
int rotate = luaL_optint(L, 1, 0);
double zoom = luaL_optnumber(L, 2, (double) 1.0);
int offset_x = luaL_optint(L, 3, 0);
int offset_y = luaL_optint(L, 4, 0);
double gamma = luaL_optnumber(L, 5, (double) -1.0);
DrawContext *dc = (DrawContext*) lua_newuserdata(L, sizeof(DrawContext));
dc->rotate = rotate;
dc->zoom = zoom;
dc->offset_x = offset_x;
dc->offset_y = offset_y;
dc->gamma = gamma;
luaL_getmetatable(L, "drawcontext");
lua_setmetatable(L, -2);
return 1;
}
static int dcSetOffset(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
dc->offset_x = luaL_checkint(L, 2);
dc->offset_y = luaL_checkint(L, 3);
return 0;
}
static int dcGetOffset(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
lua_pushinteger(L, dc->offset_x);
lua_pushinteger(L, dc->offset_y);
return 2;
}
static int dcSetRotate(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
dc->rotate = luaL_checkint(L, 2);
return 0;
}
static int dcSetZoom(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
dc->zoom = luaL_checknumber(L, 2);
return 0;
}
static int dcGetRotate(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
lua_pushinteger(L, dc->rotate);
return 1;
}
static int dcGetZoom(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
lua_pushnumber(L, dc->zoom);
return 1;
}
static int dcSetGamma(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
dc->gamma = luaL_checknumber(L, 2);
return 0;
}
static int dcGetGamma(lua_State *L) {
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext");
lua_pushnumber(L, dc->gamma);
return 1;
}
static const struct luaL_Reg drawcontext_meth[] = {
{"setRotate", dcSetRotate},
{"getRotate", dcGetRotate},
{"setZoom", dcSetZoom},
{"getZoom", dcGetZoom},
{"setOffset", dcSetOffset},
{"getOffset", dcGetOffset},
{"setGamma", dcSetGamma},
{"getGamma", dcGetGamma},
{NULL, NULL}
};
static const struct luaL_Reg drawcontext_func[] = {
{"new", newDrawContext},
{NULL, NULL}
};
int luaopen_drawcontext(lua_State *L) {
luaL_newmetatable(L, "drawcontext");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, drawcontext_meth);
lua_pop(L, 1);
luaL_register(L, "DrawContext", drawcontext_func);
return 1;
}

@ -1,35 +0,0 @@
/*
KindlePDFViewer: a DC abstraction
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DRAWCONTEXT_H
#define _DRAWCONTEXT_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
typedef struct DrawContext {
int rotate;
double zoom;
double gamma;
int offset_x;
int offset_y;
} DrawContext;
int luaopen_drawcontext(lua_State *L);
#endif

@ -1,462 +0,0 @@
/*
KindlePDFViewer: eink framebuffer access
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#include "einkfb.h"
#ifdef EMULATE_READER
int emu_w = EMULATE_READER_W;
int emu_h = EMULATE_READER_H;
#else
static void (*einkUpdateFunc)(FBInfo *fb, lua_State *L) = NULL;
inline void fbInvert4BppTo8Bpp(FBInfo *fb) {
int i = 0, j = 0, h = 0, w = 0, pitch = 0, fb_pitch = 0;
uint8_t *shadow_buf = NULL, *fb_buf = NULL;
shadow_buf = fb->buf->data;
fb_buf = fb->real_buf->data;
h = fb->buf->h;
w = fb->buf->w;
pitch = fb->buf->pitch;
fb_pitch = fb->real_buf->pitch;
/* copy bitmap from 4bpp shadow blitbuffer to framebuffer */
for (i = (h-1); i >= 0; i--) {
for (j = (w-1)/2; j >= 0; j--) {
fb_buf[i*fb_pitch + j*2] = shadow_buf[i*pitch + j];
fb_buf[i*fb_pitch + j*2] &= 0xF0;
fb_buf[i*fb_pitch + j*2] |= shadow_buf[i*pitch + j]>>4 & 0x0F;
fb_buf[i*fb_pitch + j*2 + 1] = shadow_buf[i*pitch + j];
fb_buf[i*fb_pitch + j*2 + 1] &= 0x0F;
fb_buf[i*fb_pitch + j*2 + 1] |= shadow_buf[i*pitch + j]<<4 & 0xF0;
}
}
}
inline void fb4BppTo8Bpp(FBInfo *fb) {
int i = 0, j = 0, h = 0, w = 0, pitch = 0, fb_pitch = 0;
uint8_t *shadow_buf = NULL, *fb_buf = NULL;
shadow_buf = fb->buf->data;
fb_buf = fb->real_buf->data;
/* h is 1024 for PaperWhite's shadow buffer */
h = fb->buf->h;
/* w is 758 for PaperWhite's shadow buffer */
w = fb->buf->w;
/* pitch is 376 for shadow buffer */
pitch = fb->buf->pitch;
/* pitch is 768 for PaperWhite's framebuffer */
fb_pitch = fb->real_buf->pitch;
/* copy bitmap from 4bpp shadow blitbuffer to framebuffer */
for (i = (h-1); i >= 0; i--) {
for (j = (w-1)/2; j >= 0; j--) {
fb_buf[i*fb_pitch + j*2] = shadow_buf[i*pitch + j];
fb_buf[i*fb_pitch + j*2] &= 0xF0;
fb_buf[i*fb_pitch + j*2] |= shadow_buf[i*pitch + j]>>4 & 0x0F;
fb_buf[i*fb_pitch + j*2] = ~fb_buf[i*fb_pitch + j*2];
fb_buf[i*fb_pitch + j*2 + 1] = shadow_buf[i*pitch + j];
fb_buf[i*fb_pitch + j*2 + 1] &= 0x0F;
fb_buf[i*fb_pitch + j*2 + 1] |= shadow_buf[i*pitch + j]<<4 & 0xF0;
fb_buf[i*fb_pitch + j*2 + 1] = ~fb_buf[i*fb_pitch + j*2 + 1];
}
}
}
inline void fillUpdateAreaT(update_area_t *myarea, FBInfo *fb, lua_State *L) {
int fxtype = luaL_optint(L, 2, 0);
myarea->x1 = luaL_optint(L, 3, 0);
myarea->y1 = luaL_optint(L, 4, 0);
myarea->x2 = myarea->x1 + luaL_optint(L, 5, fb->vinfo.xres);
myarea->y2 = myarea->y1 + luaL_optint(L, 6, fb->vinfo.yres);
myarea->buffer = NULL;
myarea->which_fx = fxtype ? fx_update_partial : fx_update_full;
}
inline void fillMxcfbUpdateData(mxcfb_update_data *myarea, FBInfo *fb, lua_State *L) {
myarea->update_mode = ((luaL_optint(L, 2, 0) == 0)? 1:0);
myarea->update_region.top = luaL_optint(L, 3, 0);
myarea->update_region.left = luaL_optint(L, 4, 0);
myarea->update_region.width = luaL_optint(L, 5, fb->vinfo.xres);
myarea->update_region.height = luaL_optint(L, 6, fb->vinfo.yres);
myarea->waveform_mode = 257;
myarea->update_marker = 1;
myarea->hist_bw_waveform_mode = 0;
myarea->hist_gray_waveform_mode = 0;
myarea->temp = 0x1001;
/*@TODO make the flag configurable from UI,
* this flag invert all the pixels on display 09.01 2013 (houqp)*/
myarea->flags = 0;
/*myarea->alt_buffer_data.virt_addr = NULL;*/
myarea->alt_buffer_data.phys_addr = NULL;
myarea->alt_buffer_data.width = 0;
myarea->alt_buffer_data.height = 0;
myarea->alt_buffer_data.alt_update_region.top = 0;
myarea->alt_buffer_data.alt_update_region.left = 0;
myarea->alt_buffer_data.alt_update_region.width = 0;
myarea->alt_buffer_data.alt_update_region.height = 0;
}
void kindle3einkUpdate(FBInfo *fb, lua_State *L) {
update_area_t myarea;
fillUpdateAreaT(&myarea, fb, L);
ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea);
}
void kindle4einkUpdate(FBInfo *fb, lua_State *L) {
update_area_t myarea;
fbInvert4BppTo8Bpp(fb);
fillUpdateAreaT(&myarea, fb, L);
ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea);
}
/* for kindle firmware with version >= 5.1, 5.0 is not supported for now */
void kindle51einkUpdate(FBInfo *fb, lua_State *L) {
mxcfb_update_data myarea;
fb4BppTo8Bpp(fb);
fillMxcfbUpdateData(&myarea, fb, L);
ioctl(fb->fd, MXCFB_SEND_UPDATE, &myarea);
}
#endif
static int openFrameBuffer(lua_State *L) {
const char *fb_device = luaL_checkstring(L, 1);
FBInfo *fb = (FBInfo*) lua_newuserdata(L, sizeof(FBInfo));
uint8_t *fb_map_address = NULL;
luaL_getmetatable(L, "einkfb");
fb->buf = (BlitBuffer*) lua_newuserdata(L, sizeof(BlitBuffer));
luaL_getmetatable(L, "blitbuffer");
lua_setmetatable(L, -2);
lua_setfield(L, -2, "bb");
lua_setmetatable(L, -2);
#ifndef EMULATE_READER
/* open framebuffer */
fb->fd = open(fb_device, O_RDWR);
if (fb->fd == -1) {
return luaL_error(L, "cannot open framebuffer %s",
fb_device);
}
/* initialize data structures */
memset(&fb->finfo, 0, sizeof(fb->finfo));
memset(&fb->vinfo, 0, sizeof(fb->vinfo));
/* Get fixed screen information */
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo)) {
return luaL_error(L, "cannot get screen info");
}
if (fb->finfo.type != FB_TYPE_PACKED_PIXELS) {
return luaL_error(L, "video type %x not supported",
fb->finfo.type);
}
if (strncmp(fb->finfo.id, "mxc_epdc_fb", 11) == 0) {
/* Kindle PaperWhite and KT with 5.1 or later firmware */
einkUpdateFunc = &kindle51einkUpdate;
} else if (strncmp(fb->finfo.id, "eink_fb", 7) == 0) {
if (fb->vinfo.bits_per_pixel == 8) {
/* kindle4 */
einkUpdateFunc = &kindle4einkUpdate;
} else {
/* kindle2, 3, DXG */
einkUpdateFunc = &kindle3einkUpdate;
}
} else {
return luaL_error(L, "eink model %s not supported",
fb->finfo.id);
}
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo)) {
return luaL_error(L, "cannot get variable screen info");
}
if (!fb->vinfo.grayscale) {
return luaL_error(L, "only grayscale is supported but framebuffer says it isn't");
}
if (fb->vinfo.xres <= 0 || fb->vinfo.yres <= 0) {
return luaL_error(L, "invalid resolution %dx%d.\n",
fb->vinfo.xres, fb->vinfo.yres);
}
/* mmap the framebuffer */
fb_map_address = mmap(0, fb->finfo.smem_len,
PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0);
if(fb_map_address == MAP_FAILED) {
return luaL_error(L, "cannot mmap framebuffer");
}
if (fb->vinfo.bits_per_pixel == 8) {
/* for 8bpp K4, PaperWhite, we create a shadow 4bpp blitbuffer.
* These models use 16 scale 8bpp framebuffer, so they are
* actually fake 8bpp FB. Therefore, we still treat them as 4bpp
*
* For PaperWhite, the screen width is 758, but FB's line_length
* is 768. So when doing the screen update, you still need to
* fill 768 pixels per line, but the trailing 10 px for each
* line is actually ignored by driver.
* */
fb->buf->pitch = fb->vinfo.xres / 2;
fb->buf->data = (uint8_t *)calloc(fb->buf->pitch * fb->vinfo.yres, sizeof(uint8_t));
if (!fb->buf->data) {
return luaL_error(L, "failed to allocate memory for framebuffer's shadow blitbuffer!");
}
fb->buf->allocated = 1;
/* now setup framebuffer map */
fb->real_buf = (BlitBuffer *)malloc(sizeof(BlitBuffer));
if (!fb->buf->data) {
return luaL_error(L, "failed to allocate memory for framebuffer's blitbuffer!");
}
fb->real_buf->pitch = fb->finfo.line_length;
fb->real_buf->w = fb->vinfo.xres;
fb->real_buf->h = fb->vinfo.yres;
fb->real_buf->allocated = 0;
fb->real_buf->data = fb_map_address;
} else {
fb->buf->pitch = fb->finfo.line_length;
/* for K2, K3 and DXG, we map framebuffer to fb->buf->data directly */
fb->real_buf = NULL;
fb->buf->data = fb_map_address;
fb->buf->allocated = 0;
}
#else
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
return luaL_error(L, "cannot initialize SDL.");
}
if(!(fb->screen = SDL_SetVideoMode(emu_w, emu_h, 32, SDL_HWSURFACE))) {
return luaL_error(L, "can't get video surface %dx%d for 32bpp.",
emu_w, emu_h);
}
fb->vinfo.xres = emu_w;
fb->vinfo.yres = emu_h;
fb->buf->pitch = (emu_w + 1) / 2;
fb->buf->data = calloc(fb->buf->pitch * emu_h, sizeof(char));
if(fb->buf->data == NULL) {
return luaL_error(L, "cannot get framebuffer emu memory");
}
#endif
fb->buf->w = fb->vinfo.xres;
fb->buf->h = fb->vinfo.yres;
memset(fb->buf->data, 0, fb->buf->pitch * fb->buf->h);
return 1;
}
static int getSize(lua_State *L) {
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
lua_pushinteger(L, fb->vinfo.xres);
lua_pushinteger(L, fb->vinfo.yres);
return 2;
}
static int getPitch(lua_State *L) {
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
/* for 8bpp devices, the pitch here is line_length/2, not
* the original pitch, i.e. fb->real_buf->pitch */
lua_pushinteger(L, fb->buf->pitch);
return 1;
}
static int closeFrameBuffer(lua_State *L) {
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
// should be save if called twice
if(fb->buf != NULL && fb->buf->data != NULL) {
#ifndef EMULATE_READER
if (fb->vinfo.bits_per_pixel != 4) {
munmap(fb->real_buf->data, fb->finfo.smem_len);
free(fb->buf->data);
} else {
munmap(fb->buf->data, fb->finfo.smem_len);
}
close(fb->fd);
#else
free(fb->buf->data);
#endif
fb->buf->data = NULL;
// the blitbuffer in fb->buf should be freed
// by the Lua GC when our object is garbage
// collected sice it is visible as an entry
// in the fb table
}
return 0;
}
static int einkUpdate(lua_State *L) {
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
// for Kindle e-ink display
#ifndef EMULATE_READER
einkUpdateFunc(fb, L);
#else
int fxtype = luaL_optint(L, 2, 0);
// for now, we only do fullscreen blits in emulation mode
if (fxtype == 0) {
// simmulate a full screen update in eink screen
if(SDL_MUSTLOCK(fb->screen) && (SDL_LockSurface(fb->screen) < 0)) {
return luaL_error(L, "can't lock surface.");
}
SDL_FillRect(fb->screen, NULL, 0x000000);
if(SDL_MUSTLOCK(fb->screen)) SDL_UnlockSurface(fb->screen);
SDL_Flip(fb->screen);
}
if(SDL_MUSTLOCK(fb->screen) && (SDL_LockSurface(fb->screen) < 0)) {
return luaL_error(L, "can't lock surface.");
}
int x1 = luaL_optint(L, 3, 0);
int y1 = luaL_optint(L, 4, 0);
int w = luaL_optint(L, 5, fb->vinfo.xres);
int h = luaL_optint(L, 6, fb->vinfo.yres);
int x, y;
for(y = y1; y < y1+h; y++) {
uint32_t *sfptr = (uint32_t*)(fb->screen->pixels + y*fb->screen->pitch);
for(x = x1; x < x1+w; x+=2) {
uint8_t value = fb->buf->data[y*fb->buf->pitch + x/2];
sfptr[x] = SDL_MapRGB(fb->screen->format,
255 - (value & 0xF0),
255 - (value & 0xF0),
255 - (value & 0xF0));
sfptr[x+1] = SDL_MapRGB(fb->screen->format,
255 - ((value & 0x0F) << 4),
255 - ((value & 0x0F) << 4),
255 - ((value & 0x0F) << 4));
}
}
if(SDL_MUSTLOCK(fb->screen)) SDL_UnlockSurface(fb->screen);
SDL_Flip(fb->screen);
#endif
return 0;
}
/* NOTICE!!! You must close and reopen framebuffer after called this method.
* Otherwise, screen resolution will not be updated! */
static int einkSetOrientation(lua_State *L) {
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
int mode = luaL_optint(L, 2, 0);
if (mode < 0 || mode > 3) {
return luaL_error(L, "Wrong rotation mode %d given!", mode);
}
/* ioctl has a different definition for rotation mode.
* 1
* +--------------+
* | +----------+ |
* | | | |
* | | Freedom! | |
* | | | |
* | | | |
* 3 | | | | 2
* | | | |
* | | | |
* | +----------+ |
* | |
* | |
* +--------------+
* 0
* */
#ifndef EMULATE_READER
if (mode == 1)
mode = 2;
else if (mode == 2)
mode = 1;
ioctl(fb->fd, FBIO_EINK_SET_DISPLAY_ORIENTATION, mode);
#else
if (mode == 0 || mode == 2) {
emu_w = EMULATE_READER_W;
emu_h = EMULATE_READER_H;
}
else if (mode == 1 || mode == 3) {
emu_w = EMULATE_READER_H;
emu_h = EMULATE_READER_W;
}
#endif
return 0;
}
static int einkGetOrientation(lua_State *L) {
int mode = 0;
#ifndef EMULATE_READER
FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb");
ioctl(fb->fd, FBIO_EINK_GET_DISPLAY_ORIENTATION, &mode);
/* adjust ioctl's rotate mode definition to KPV's
* refer to screen.lua */
if (mode == 2)
mode = 1;
else if (mode == 1)
mode = 2;
#else
if (emu_w == EMULATE_READER_H || emu_h == EMULATE_READER_W)
mode = 1;
#endif
lua_pushinteger(L, mode);
return 1;
}
static const struct luaL_Reg einkfb_func[] = {
{"open", openFrameBuffer},
{NULL, NULL}
};
static const struct luaL_Reg einkfb_meth[] = {
{"close", closeFrameBuffer},
{"__gc", closeFrameBuffer},
{"refresh", einkUpdate},
{"getOrientation", einkGetOrientation},
{"setOrientation", einkSetOrientation},
{"getSize", getSize},
{"getPitch", getPitch},
{NULL, NULL}
};
int luaopen_einkfb(lua_State *L) {
luaL_newmetatable(L, "einkfb");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, einkfb_meth);
luaL_register(L, "einkfb", einkfb_func);
return 1;
}

@ -1,53 +0,0 @@
/*
KindlePDFViewer: eink framebuffer access
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PDF_EINKFB_H
#define _PDF_EINKFB_H
#ifdef EMULATE_READER
#include <SDL.h>
struct fb_var_screeninfo {
uint32_t xres;
uint32_t yres;
};
#else
#include <linux/fb.h>
#include "include/einkfb.h"
#include "include/mxcfb.h"
#endif
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "blitbuffer.h"
typedef struct FBInfo {
int fd;
BlitBuffer *buf;
BlitBuffer *real_buf;
#ifdef EMULATE_READER
SDL_Surface *screen;
#else
struct fb_fix_screeninfo finfo;
#endif
struct fb_var_screeninfo vinfo;
} FBInfo;
int luaopen_einkfb(lua_State *L);
#endif

@ -1,47 +0,0 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pprint
import struct
import argparse
EV_LOG = "ev_double.log"
EV_PIPE = "emu_event"
def gen_ev_from_log_entry(line):
values = line.split("|")
return {
"time": {
"sec": int(values[3]),
"usec": int(values[4]),
},
"type": int(values[0]),
"code": int(values[1]),
"value": int(values[2]),
}
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("ev_log", type=str,
help="event log file to replay")
args = parser.parse_args()
# parse ev log into dictionaries
evs = [gen_ev_from_log_entry(line.strip())
for line in open(args.ev_log)]
#pprint.pprint(evs)
# replay evs
ev_pipe = open(EV_PIPE, "w")
for ev in evs:
#@TODO also simulate timing here 25.02 2013 (houqp)
ev_pipe.write(
struct.pack("llHHi",
ev["time"]["sec"], ev["time"]["usec"],
ev["type"],
ev["code"],
ev["value"])
)

105
extr.c

@ -1,105 +0,0 @@
/*
extr: Extract attachments from PDF file
Usage: extr /dir/file.pdf pageno
Returns 0 if one or more attachments saved, otherwise returns non-zero.
Prints the number of saved attachments on stdout.
Attachments are saved in /dir directory with the appropriate filenames.
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mupdf-internal.h"
#include <libgen.h>
static pdf_document *doc;
void dump_stream(int i, FILE *fout)
{
fz_stream *stm = pdf_open_stream(doc, i, 0);
static unsigned char buf[8192];
while (1) {
int n = fz_read(stm, buf, sizeof buf);
if (n == 0) break;
fwrite(buf, 1, n, fout);
}
fz_close(stm);
}
/* returns the number of attachments saved */
int save_attachments(int pageno, char *targetdir)
{
pdf_page *page = pdf_load_page(doc, pageno-1);
pdf_annot *annot;
int saved_count = 0;
for (annot = page->annots; annot ; annot = annot->next) {
pdf_obj *fs_obj = pdf_dict_gets(annot->obj, "FS");
if (fs_obj) {
pdf_obj *ef_obj;
char *name = basename(strdup(pdf_to_str_buf(pdf_dict_gets(fs_obj, "F"))));
ef_obj = pdf_dict_gets(fs_obj, "EF");
if (ef_obj) {
pdf_obj *f_obj = pdf_dict_gets(ef_obj, "F");
if (f_obj && pdf_is_indirect(f_obj)) {
static char pathname[PATH_MAX];
sprintf(pathname, "%s/%s", targetdir, name);
FILE *fout = fopen(pathname, "w");
if (!fout) {
fprintf(stderr, "extr: cannot write to file %s\n", pathname);
exit(1);
}
dump_stream(pdf_to_num(f_obj), fout);
fclose(fout);
saved_count++;
}
}
}
}
return saved_count;
}
int main(int argc, char *argv[])
{
int saved = 0;
if (argc != 3) {
printf("Usage: extr file.pdf pageno\n");
exit(1);
}
char *filename = strdup(argv[1]);
char *dir = dirname(strdup(filename));
int pageno = atoi(argv[2]);
fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
if (!ctx) {
fprintf(stderr, "extr: cannot create context\n");
exit(1);
}
fz_var(doc);
fz_try(ctx) {
doc = pdf_open_document(ctx, filename);
saved = save_attachments(pageno, dir);
}
fz_catch(ctx)
{
}
printf("%d\n", saved);
return 0;
}

203
ft.c

@ -1,203 +0,0 @@
/*
KindlePDFViewer: FreeType font rastering for UI
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
//#include <stdio.h>
#include <stdint.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "blitbuffer.h"
/* for font access: */
#include <pdf/mupdf-internal.h>
#include "ft.h"
FT_Library freetypelib;
typedef struct KPVFace {
FT_Face face;
int allocated_face;
} KPVFace;
static int newFace(lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
int pxsize = luaL_optint(L, 2, 16*64);
KPVFace *face = (KPVFace*) lua_newuserdata(L, sizeof(KPVFace));
luaL_getmetatable(L, "ft_face");
lua_setmetatable(L, -2);
face->allocated_face = 0;
FT_Error error = FT_New_Face(freetypelib, filename, 0, &face->face);
if(error) {
return luaL_error(L, "freetype error");
}
face->allocated_face = 1;
error = FT_Set_Pixel_Sizes(face->face, 0, pxsize);
if(error) {
error = FT_Done_Face(face->face);
return luaL_error(L, "freetype error");
}
if(face->face->charmap == NULL) {
//TODO
//fprintf(stderr, "no unicode charmap found, to be implemented.\n");
}
return 1;
}
static int renderGlyph(lua_State *L) {
KPVFace *face = (KPVFace*) luaL_checkudata(L, 1, "ft_face");
int ch = luaL_checkint(L, 2);
double bg = luaL_checknumber(L, 3);
double fg = luaL_checknumber(L, 4);
FT_Error error = FT_Load_Char(face->face, ch, FT_LOAD_RENDER);
if(error) {
return luaL_error(L, "freetype error");
}
int w = face->face->glyph->bitmap.width;
int h = face->face->glyph->bitmap.rows;
lua_newtable(L);
BlitBuffer *bb;
int result = newBlitBufferNative(L, w, h, 0, &bb);
if(result != 1) {
return result;
}
lua_setfield(L, -2, "bb");
uint8_t *dst = bb->data;
int y;
int x;
for(y = 0; y < h; y++) {
uint8_t *src = face->face->glyph->bitmap.buffer + y * face->face->glyph->bitmap.pitch;
for(x = 0; x < (w/2); x++) {
*dst = (int)(0xFF * bg - src[0] * (bg - fg)) & 0xF0 |
(int)(0xFF * bg - src[1] * (bg - fg)) >> 4;
src+=2;
dst++;
}
if(w & 1) {
*dst = (int)(0xFF * bg - *src * (bg - fg)) & 0xF0;
dst++;
}
}
lua_pushinteger(L, face->face->glyph->bitmap_left);
lua_setfield(L, -2, "l");
lua_pushinteger(L, face->face->glyph->bitmap_top);
lua_setfield(L, -2, "t");
lua_pushinteger(L, face->face->glyph->metrics.horiAdvance >> 6);
lua_setfield(L, -2, "r");
lua_pushinteger(L, face->face->glyph->advance.x >> 6);
lua_setfield(L, -2, "ax");
lua_pushinteger(L, face->face->glyph->advance.y >> 6);
lua_setfield(L, -2, "ay");
return 1;
}
static int hasKerning(lua_State *L) {
KPVFace *face = (KPVFace*) luaL_checkudata(L, 1, "ft_face");
if(FT_HAS_KERNING((face->face))) {
lua_pushinteger(L, 1);
} else {
lua_pushinteger(L, 0);
}
return 1;
}
static int getKerning(lua_State *L) {
KPVFace *face = (KPVFace*) luaL_checkudata(L, 1, "ft_face");
int left = FT_Get_Char_Index(face->face, luaL_checkint(L, 2));
int right = FT_Get_Char_Index(face->face, luaL_checkint(L, 3));
FT_Vector kerning;
FT_Error error = FT_Get_Kerning(face->face, left, right, FT_KERNING_DEFAULT, &kerning);
if(error) {
return luaL_error(L, "freetype error when getting kerning (l=%d, r=%d)", left, right);
}
lua_pushinteger(L, kerning.x >> 6);
return 1;
}
static int getHeightAndAscender(lua_State *L) {
KPVFace *face = (KPVFace*) luaL_checkudata(L, 1, "ft_face");
double pixels_height,pixels_ascender;
double em_size, y_scale;
/* compute floating point scale factors */
em_size = 1.0 * face->face->units_per_EM;
y_scale = face->face->size->metrics.y_ppem / em_size;
/* convert design distances to floating point pixels */
pixels_height = face->face->height * y_scale;
pixels_ascender = face->face->ascender * y_scale;
lua_pushnumber(L, pixels_height);
lua_pushnumber(L, pixels_ascender);
return 2;
}
static int doneFace(lua_State *L) {
KPVFace *face = (KPVFace*) luaL_checkudata(L, 1, "ft_face");
if(face->allocated_face) {
FT_Error error = FT_Done_Face(face->face);
if(error) {
return luaL_error(L, "freetype error when freeing face");
}
}
return 0;
}
static const struct luaL_Reg ft_face_meth[] = {
{"renderGlyph", renderGlyph},
{"hasKerning", hasKerning},
{"getKerning", getKerning},
{"getHeightAndAscender", getHeightAndAscender},
{"done", doneFace},
{"__gc", doneFace},
{NULL, NULL}
};
static const struct luaL_Reg ft_func[] = {
{"newFace", newFace},
{NULL, NULL}
};
int luaopen_ft(lua_State *L) {
int error = FT_Init_FreeType(&freetypelib);
if(error) {
return luaL_error(L, "freetype error on initialization");
}
luaL_newmetatable(L, "ft_face");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, ft_face_meth);
luaL_register(L, "freetype", ft_func);
return 1;
}

28
ft.h

@ -1,28 +0,0 @@
/*
KindlePDFViewer: FreeType font rastering for UI
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PDF_FT_H
#define _PDF_FT_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_ft(lua_State *L);
#endif

@ -1,438 +0,0 @@
/*
KindlePDFViewer: input abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "popen-noshell/popen_noshell.h"
#include <err.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/input.h>
#ifdef EMULATE_READER
#include <SDL.h>
#endif
#include "input.h"
#include <sys/types.h>
#include <sys/wait.h>
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
#define CODE_USB_PLUG_IN 10010
#define CODE_USB_PLUG_OUT 10011
#define CODE_CHARGING 10020
#define CODE_NOT_CHARGING 10021
#define NUM_FDS 4
int inputfds[4] = { -1, -1, -1, -1 };
#ifndef EMULATE_READER
pid_t slider_pid = -1;
struct popen_noshell_pass_to_pclose pclose_arg;
void slider_handler(int sig)
{
/* Kill lipc-wait-event properly on exit */
if(pclose_arg.pid != 0) {
// Be a little more gracious, lipc seems to handle SIGINT properly
kill(pclose_arg.pid, SIGINT);
}
}
#else
int is_in_touch = 0;
static inline void genEmuEvent(lua_State *L, int fd, int type, int code, int value) {
struct input_event input;
input.type = type;
input.code = code;
input.value = value;
gettimeofday(&input.time, NULL);
if(write(fd, &input, sizeof(struct input_event)) == -1) {
luaL_error(L, "Failed to generate emu event.\n");
}
return;
}
#endif
int findFreeFdSlot() {
int i;
for(i=0; i<NUM_FDS; i++) {
if(inputfds[i] == -1) {
return i;
}
}
return -1;
}
static int openInputDevice(lua_State *L) {
const char* inputdevice = luaL_checkstring(L, 1);
#ifndef EMULATE_READER
int fd;
int childpid;
fd = findFreeFdSlot();
if(fd == -1) {
return luaL_error(L, "no free slot for new input device <%s>", inputdevice);
}
if(!strcmp("fake_events", inputdevice)) {
/* special case: the power slider */
int pipefd[2];
pipe(pipefd);
if((childpid = fork()) == -1) {
return luaL_error(L, "cannot fork() slider event listener");
}
if(childpid == 0) {
// We send a SIGTERM to this child on exit, trap it to kill lipc properly.
signal(SIGTERM, slider_handler);
FILE *fp;
char std_out[256];
int status;
struct input_event ev;
__u16 key_code = 10000;
close(pipefd[0]);
ev.type = EV_KEY;
ev.code = key_code;
ev.value = 1;
/* listen power slider events (listen for ever for multiple events) */
char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver,charging,notCharging", (char *) NULL};
/* @TODO 07.06 2012 (houqp)
* plugin and out event can only be watched by:
lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn
*/
fp = popen_noshell("lipc-wait-event", (const char * const *)argv, "r", &pclose_arg, 0);
if (!fp) {
err(EXIT_FAILURE, "popen_noshell()");
}
/* Flush to get rid of buffering issues? */
fflush(fp);
while(fgets(std_out, sizeof(std_out)-1, fp)) {
if(std_out[0] == 'g') {
ev.code = CODE_IN_SAVER;
} else if(std_out[0] == 'o') {
ev.code = CODE_OUT_SAVER;
} else if((std_out[0] == 'u') && (std_out[7] == 'I')) {
ev.code = CODE_USB_PLUG_IN;
} else if((std_out[0] == 'u') && (std_out[7] == 'O')) {
ev.code = CODE_USB_PLUG_OUT;
} else if(std_out[0] == 'c') {
ev.code = CODE_CHARGING;
} else if(std_out[0] == 'n') {
ev.code = CODE_NOT_CHARGING;
} else {
printf("Unrecognized event.\n");
}
/* fill event struct */
gettimeofday(&ev.time, NULL);
/* generate event */
if(write(pipefd[1], &ev, sizeof(struct input_event)) == -1) {
printf("Failed to generate event.\n");
}
}
status = pclose_noshell(&pclose_arg);
if (status == -1) {
err(EXIT_FAILURE, "pclose_noshell()");
} else {
printf("lipc-wait-event exited with status %d.\n", status);
if WIFEXITED(status) {
printf("lipc-wait-event exited normally with status: %d.\n", WEXITSTATUS(status));
}
if WIFSIGNALED(status) {
printf("lipc-wait-event terminated by signal: %d.\n", WTERMSIG(status));
}
}
// We're done, go away :).
_exit(EXIT_SUCCESS);
} else {
close(pipefd[1]);
inputfds[fd] = pipefd[0];
slider_pid = childpid;
}
} else {
inputfds[fd] = open(inputdevice, O_RDONLY | O_NONBLOCK, 0);
if(inputfds[fd] != -1) {
ioctl(inputfds[fd], EVIOCGRAB, 1);
return 0;
} else {
return luaL_error(L, "error opening input device <%s>: %d", inputdevice, errno);
}
}
#else
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
return luaL_error(L, "cannot initialize SDL.");
}
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
/* we only use inputfds[0] in emu mode, because we only have one
* fake device so far. */
inputfds[0] = open(inputdevice, O_RDWR | O_NONBLOCK);
if (inputfds < 0) {
return luaL_error(L, "error opening input device <%s>: %d", inputdevice, errno);
}
#endif
return 0;
}
static int closeInputDevices(lua_State *L) {
int i;
for(i=0; i<NUM_FDS; i++) {
if(inputfds[i] != -1) {
ioctl(inputfds[i], EVIOCGRAB, 0);
close(inputfds[i]);
}
}
#ifndef EMULATE_READER
if(slider_pid != -1) {
/* kill and wait for child process */
kill(slider_pid, SIGTERM);
waitpid(-1, NULL, 0);
}
return 0;
#else
close(inputfds[0]);
SDL_Quit();
return 0;
#endif
}
static int fakeTapInput(lua_State *L) {
#ifndef EMULATE_READER
const char* inputdevice = luaL_checkstring(L, 1);
int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3);
int i;
int inputfd = -1;
struct input_event ev;
inputfd = open(inputdevice, O_WRONLY | O_NDELAY);
if (inputfd == NULL) {
return luaL_error(L, "cannot open input device <%s>", inputdevice);
}
if(inputfd != -1) {
gettimeofday(&ev.time, NULL);
ev.type = 3;
ev.code = 57;
ev.value = 0;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 3;
ev.code = 53;
ev.value = x;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 3;
ev.code = 54;
ev.value = y;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 1;
ev.code = 330;
ev.value = 1;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 1;
ev.code = 325;
ev.value = 1;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 0;
ev.code = 0;
ev.value = 0;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 3;
ev.code = 57;
ev.value = -1;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 1;
ev.code = 330;
ev.value = 0;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 1;
ev.code = 325;
ev.value = 0;
write(inputfd, &ev, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = 0;
ev.code = 0;
ev.value = 0;
write(inputfd, &ev, sizeof(ev));
}
ioctl(inputfd, EVIOCGRAB, 0);
close(inputfd);
return 0;
#else
return 0;
#endif
}
static inline void set_event_table(lua_State *L, struct input_event input) {
lua_newtable(L);
lua_pushstring(L, "type");
lua_pushinteger(L, (int) input.type);
lua_settable(L, -3);
lua_pushstring(L, "code");
lua_pushinteger(L, (int) input.code);
lua_settable(L, -3);
lua_pushstring(L, "value");
lua_pushinteger(L, (int) input.value);
lua_settable(L, -3);
lua_pushstring(L, "time");
lua_newtable(L);
lua_pushstring(L, "sec");
lua_pushinteger(L, (int) input.time.tv_sec);
lua_settable(L, -3);
lua_pushstring(L, "usec");
lua_pushinteger(L, (int) input.time.tv_usec);
lua_settable(L, -3);
lua_settable(L, -3);
}
static int waitForInput(lua_State *L) {
struct input_event input;
int n;
int usecs = luaL_optint(L, 1, -1); // we check for <0 later
#ifndef EMULATE_READER
fd_set fds;
struct timeval timeout;
int i, num, nfds;
timeout.tv_sec = (usecs/1000000);
timeout.tv_usec = (usecs%1000000);
nfds = 0;
FD_ZERO(&fds);
for(i=0; i<NUM_FDS; i++) {
if(inputfds[i] != -1)
FD_SET(inputfds[i], &fds);
if(inputfds[i] + 1 > nfds)
nfds = inputfds[i] + 1;
}
/* when no value is given as argument, we pass
* NULL to select() for the timeout value, setting no
* timeout at all.
*/
num = select(nfds, &fds, NULL, NULL, (usecs < 0) ? NULL : &timeout);
if (num == 0) {
return luaL_error(L, "Waiting for input failed: timeout\n");
} else if (num < 0) {
return luaL_error(L, "Waiting for input failed: %d\n", errno);
}
for(i=0; i<NUM_FDS; i++) {
if(inputfds[i] != -1 && FD_ISSET(inputfds[i], &fds)) {
n = read(inputfds[i], &input, sizeof(struct input_event));
if(n == sizeof(struct input_event)) {
set_event_table(L, input);
return 1;
}
}
}
#else
SDL_Event event;
while(1) {
/* so far we only use inputfds[0] in emu mode */
n = read(inputfds[0], &input, sizeof(struct input_event));
if(n == sizeof(struct input_event)) {
set_event_table(L, input);
return 1;
}
int ticks = SDL_GetTicks();
if (usecs < 0) {
SDL_WaitEvent(&event);
}
else {
while (SDL_GetTicks()-ticks <= usecs/1000) {
if (SDL_PollEvent(&event)) break;
SDL_Delay(10);
}
if (SDL_GetTicks()-ticks > usecs/1000)
return luaL_error(L, "Waiting for input failed: timeout\n");
}
switch(event.type) {
case SDL_KEYDOWN:
genEmuEvent(L, inputfds[0], EV_KEY, event.key.keysym.scancode, 1);
break;
case SDL_KEYUP:
genEmuEvent(L, inputfds[0], EV_KEY, event.key.keysym.scancode, 0);
break;
case SDL_MOUSEMOTION:
if (is_in_touch) {
if (event.motion.xrel != 0)
genEmuEvent(L, inputfds[0], EV_ABS, ABS_MT_POSITION_X, event.button.x);
if (event.motion.yrel != 0)
genEmuEvent(L, inputfds[0], EV_ABS, ABS_MT_POSITION_Y, event.button.y);
genEmuEvent(L, inputfds[0], EV_SYN, SYN_REPORT, 0);
}
break;
case SDL_MOUSEBUTTONUP:
is_in_touch = 0;
genEmuEvent(L, inputfds[0], EV_ABS, ABS_MT_TRACKING_ID, -1);
genEmuEvent(L, inputfds[0], EV_SYN, SYN_REPORT, 0);
break;
case SDL_MOUSEBUTTONDOWN:
/* use mouse click to simulate single tap */
is_in_touch = 1;
genEmuEvent(L, inputfds[0], EV_ABS, ABS_MT_TRACKING_ID, 0);
genEmuEvent(L, inputfds[0], EV_ABS, ABS_MT_POSITION_X, event.button.x);
genEmuEvent(L, inputfds[0], EV_ABS, ABS_MT_POSITION_Y, event.button.y);
genEmuEvent(L, inputfds[0], EV_SYN, SYN_REPORT, 0);
/*printf("Mouse button %d pressed at (%d,%d)\n",*/
/*event.button.button, event.button.x, event.button.y);*/
break;
case SDL_QUIT:
return luaL_error(L, "application forced to quit");
}
}
#endif
return 0;
}
static const struct luaL_Reg input_func[] = {
{"open", openInputDevice},
{"closeAll", closeInputDevices},
{"waitForEvent", waitForInput},
{"fakeTapInput", fakeTapInput},
{NULL, NULL}
};
int luaopen_input(lua_State *L) {
luaL_register(L, "input", input_func);
return 1;
}

@ -1,28 +0,0 @@
/*
KindlePDFViewer: input abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PDF_INPUT_H
#define _PDF_INPUT_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_input(lua_State *L);
#endif

@ -1,287 +0,0 @@
/*
KindlePDFViewer: a KOPTContext abstraction
Copyright (C) 2012 Huang Xin <chrox.huang@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "koptcontext.h"
static int newKOPTContext(lua_State *L) {
int trim = 1;
int wrap = 1;
int indent = 1;
int rotate = 0;
int columns = 2;
int offset_x = 0;
int offset_y = 0;
int dev_dpi = 167;
int dev_width = 600;
int dev_height = 800;
int page_width = 600;
int page_height = 800;
int straighten = 0;
int justification = -1;
int read_max_width = 3000;
int read_max_height = 4000;
double zoom = 1.0;
double margin = 0.06;
double quality = 1.0;
double contrast = 1.0;
double defect_size = 1.0;
double line_spacing = 1.2;
double word_spacing = 1.375;
double shrink_factor = 0.9;
uint8_t *data = NULL;
BBox bbox = {0, 0, 0, 0};
WILLUSBITMAP *src;
int precache = 0;
KOPTContext *kc = (KOPTContext*) lua_newuserdata(L, sizeof(KOPTContext));
kc->trim = trim;
kc->wrap = wrap;
kc->indent = indent;
kc->rotate = rotate;
kc->columns = columns;
kc->offset_x = offset_x;
kc->offset_y = offset_y;
kc->dev_dpi = dev_dpi;
kc->dev_width = dev_width;
kc->dev_height = dev_height;
kc->page_width = page_width;
kc->page_height = page_height;
kc->straighten = straighten;
kc->justification = justification;
kc->read_max_width = read_max_width;
kc->read_max_height = read_max_height;
kc->zoom = zoom;
kc->margin = margin;
kc->quality = quality;
kc->contrast = contrast;
kc->defect_size = defect_size;
kc->line_spacing = line_spacing;
kc->word_spacing = word_spacing;
kc->shrink_factor = shrink_factor;
kc->data = data;
kc->bbox = bbox;
kc->src = src;
kc->precache = precache;
luaL_getmetatable(L, "koptcontext");
lua_setmetatable(L, -2);
return 1;
}
static int kcSetBBox(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->bbox.x0 = luaL_checknumber(L, 2);
kc->bbox.y0 = luaL_checknumber(L, 3);
kc->bbox.x1 = luaL_checknumber(L, 4);
kc->bbox.y1 = luaL_checknumber(L, 5);
return 0;
}
static int kcSetTrim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->trim = luaL_checkint(L, 2);
return 0;
}
static int kcGetTrim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->trim);
return 1;
}
static int kcSetWrap(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->wrap = luaL_checkint(L, 2);
return 0;
}
static int kcSetIndent(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->indent = luaL_checkint(L, 2);
return 0;
}
static int kcSetRotate(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->rotate = luaL_checkint(L, 2);
return 0;
}
static int kcSetColumns(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->columns = luaL_checkint(L, 2);
return 0;
}
static int kcSetOffset(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->offset_x = luaL_checkint(L, 2);
kc->offset_y = luaL_checkint(L, 3);
return 0;
}
static int kcGetOffset(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->offset_x);
lua_pushinteger(L, kc->offset_y);
return 2;
}
static int kcSetDeviceDPI(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->dev_dpi = luaL_checkint(L, 2);
return 0;
}
static int kcSetDeviceDim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->dev_width = luaL_checkint(L, 2);
kc->dev_height = luaL_checkint(L, 3);
return 0;
}
static int kcGetPageDim(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->page_width);
lua_pushinteger(L, kc->page_height);
return 2;
}
static int kcSetStraighten(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->straighten = luaL_checkint(L, 2);
return 0;
}
static int kcSetJustification(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->justification = luaL_checkint(L, 2);
return 0;
}
static int kcSetZoom(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->zoom = luaL_checknumber(L, 2);
return 0;
}
static int kcGetZoom(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushnumber(L, kc->zoom);
return 1;
}
static int kcSetMargin(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->margin = luaL_checknumber(L, 2);
return 0;
}
static int kcSetQuality(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->quality = luaL_checknumber(L, 2);
return 0;
}
static int kcSetContrast(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->contrast = luaL_checknumber(L, 2);
return 0;
}
static int kcSetDefectSize(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->defect_size = luaL_checknumber(L, 2);
return 0;
}
static int kcSetLineSpacing(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->line_spacing = luaL_checknumber(L, 2);
return 0;
}
static int kcSetWordSpacing(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->word_spacing = luaL_checknumber(L, 2);
return 0;
}
static int kcSetPreCache(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->precache = 1;
return 0;
}
static int kcIsPreCache(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->precache);
return 1;
}
static const struct luaL_Reg koptcontext_meth[] = {
{"setBBox", kcSetBBox},
{"setTrim", kcSetTrim},
{"getTrim", kcGetTrim},
{"setWrap", kcSetWrap},
{"setIndent", kcSetIndent},
{"setRotate", kcSetRotate},
{"setColumns", kcSetColumns},
{"setOffset", kcSetOffset},
{"getOffset", kcGetOffset},
{"setDeviceDim", kcSetDeviceDim},
{"setDeviceDPI", kcSetDeviceDPI},
{"getPageDim", kcGetPageDim},
{"setStraighten", kcSetStraighten},
{"setJustification", kcSetJustification},
{"setZoom", kcSetZoom},
{"getZoom", kcGetZoom},
{"setMargin", kcSetMargin},
{"setQuality", kcSetQuality},
{"setContrast", kcSetContrast},
{"setDefectSize", kcSetDefectSize},
{"setLineSpacing", kcSetLineSpacing},
{"setWordSpacing", kcSetWordSpacing},
{"setPreCache", kcSetPreCache},
{"isPreCache", kcIsPreCache},
{NULL, NULL}
};
static const struct luaL_Reg koptcontext_func[] = {
{"new", newKOPTContext},
{NULL, NULL}
};
int luaopen_koptcontext(lua_State *L) {
luaL_newmetatable(L, "koptcontext");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, koptcontext_meth);
lua_pop(L, 1);
luaL_register(L, "KOPTContext", koptcontext_func);
return 1;
}

@ -1,27 +0,0 @@
/*
KindlePDFViewer: a KOPTContext abstraction
Copyright (C) 2012 Huang Xin <chrox.huang@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KOPTCONTEXT_H
#define _KOPTCONTEXT_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "koptreflow.h"
int luaopen_koptcontext(lua_State *L);
#endif

@ -0,0 +1 @@
Subproject commit dc9f674dc7887b8753b002b59170a6c58f2dd3ce

@ -1,128 +0,0 @@
/*
KindlePDFViewer
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "koptcontext.h"
#include "pdf.h"
#include "mupdfimg.h"
#include "djvu.h"
#include "pic.h"
#include "cre.h"
#include "einkfb.h"
#include "input.h"
#include "ft.h"
#include "util.h"
#include "lfs.h"
lua_State *L;
/* from luajit-2.0/src/luajit.c : */
static int traceback(lua_State *L)
{
if (!lua_isstring(L, 1)) { /* Non-string error object? Try metamethod. */
if (lua_isnoneornil(L, 1) ||
!luaL_callmeta(L, 1, "__tostring") ||
!lua_isstring(L, -1))
return 1; /* Return non-string error object. */
lua_remove(L, 1); /* Replace object by result of __tostring metamethod. */
}
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1); /* Push error message. */
lua_pushinteger(L, 2); /* Skip this function and debug.traceback(). */
lua_call(L, 2, 1); /* Call debug.traceback(). */
return 1;
}
/* from luajit-2.0/src/luajit.c : */
static int docall(lua_State *L, int narg, int clear)
{
int status;
int base = lua_gettop(L) - narg; /* function index */
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
return status;
}
int main(int argc, char **argv) {
int i;
if(argc < 2) {
fprintf(stderr, "needs config file as first argument.\n");
return -1;
}
/* set up Lua state */
L = lua_open();
if(L) {
luaL_openlibs(L);
luaopen_blitbuffer(L);
luaopen_drawcontext(L);
luaopen_koptcontext(L);
luaopen_einkfb(L);
luaopen_pdf(L);
luaopen_djvu(L);
luaopen_pic(L);
luaopen_cre(L);
luaopen_input(L);
luaopen_util(L);
luaopen_ft(L);
luaopen_mupdfimg(L);
luaopen_lfs(L);
lua_newtable(L);
for(i=2; i < argc; i++) {
lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i-1);
}
lua_setglobal(L, "ARGV");
if(luaL_loadfile(L, argv[1]) || docall(L, 0, 1)) {
fprintf(stderr, "lua config error: %s\n", lua_tostring(L, -1));
lua_close(L);
L=NULL;
return -1;
}
}
return 0;
}

@ -1 +0,0 @@
Subproject commit 79ef67e1538ef431d6531a3aed5617946ed1d20f

@ -1 +0,0 @@
Subproject commit 90ce6b4e0bae768157ebbcbf0aeaf54930a0353c

@ -1 +0,0 @@
Subproject commit 149e0fb8ec6295325e1e448bbe79b7e9bf2285aa

@ -1 +0,0 @@
Subproject commit eb6f890ebd01ee4cf4f31a66d8a946bc8dccd885

@ -1 +0,0 @@
Subproject commit 05219d086a5136ee19f643cf062bd5c0d3aef5d3

@ -1,169 +0,0 @@
diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c
index 33a1a65..c2fdee3 100644
--- a/pdf/pdf_font.c
+++ b/pdf/pdf_font.c
@@ -185,7 +185,12 @@ pdf_load_builtin_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname)
if (!data)
fz_throw(ctx, "cannot find builtin font: '%s'", fontname);
+#ifndef NOBUILTINFONT
fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 1);
+#else
+ fontdesc->font = fz_new_font_from_file(ctx, fontname, data, 0, 1);
+ free(data);
+#endif
if (!strcmp(fontname, "Symbol") || !strcmp(fontname, "ZapfDingbats"))
fontdesc->flags |= PDF_FD_SYMBOLIC;
@@ -201,7 +206,12 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontnam
if (!data)
fz_throw(ctx, "cannot find substitute font");
+#ifndef NOBUILTINFONT
fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 1);
+#else
+ fontdesc->font = fz_new_font_from_file(ctx, fontname, data, 0, 1);
+ free(data);
+#endif
fontdesc->font->ft_substitute = 1;
fontdesc->font->ft_bold = bold && !ft_is_bold(fontdesc->font->ft_face);
@@ -219,7 +229,12 @@ pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fon
fz_throw(ctx, "cannot find builtin CJK font");
/* a glyph bbox cache is too big for droid sans fallback (51k glyphs!) */
+#ifndef NOBUILTINFONT
fontdesc->font = fz_new_font_from_memory(ctx, fontname, data, len, 0, 0);
+#else
+ fontdesc->font = fz_new_font_from_file(ctx, fontname, data, 0, 1);
+ free(data);
+#endif
fontdesc->font->ft_substitute = 1;
}
diff --git a/pdf/pdf_fontfile.c b/pdf/pdf_fontfile.c
index 99565da..a91380f 100644
--- a/pdf/pdf_fontfile.c
+++ b/pdf/pdf_fontfile.c
@@ -15,6 +15,8 @@
Set NODROIDFONT to use the base 14 fonts as substitute fonts.
*/
+#ifndef NOBUILTINFONT
+
#ifdef NOCJK
#define NOCJKFONT
#endif
@@ -152,3 +154,112 @@ pdf_lookup_substitute_cjk_font(int ros, int serif, unsigned int *len)
return NULL;
#endif
}
+
+#else // NOBUILTINFONT
+
+unsigned char *
+get_font_file(char *name)
+{
+ char *fontdir;
+ char *filename;
+ int len;
+ fontdir = getenv("FONTDIR");
+ if(fontdir == NULL) {
+ fontdir = "./fonts";
+ }
+ len = strlen(fontdir) + strlen(name) + 2;
+ filename = malloc(len);
+ if(filename == NULL) {
+ return NULL;
+ }
+ snprintf(filename, len, "%s/%s", fontdir, name);
+ return filename;
+}
+
+unsigned char *
+pdf_lookup_builtin_font(char *name, unsigned int *len)
+{
+ *len = 0;
+ if (!strcmp("Courier", name)) {
+ return get_font_file("NimbusMonL-Regu.cff");
+ }
+ if (!strcmp("Courier-Bold", name)) {
+ return get_font_file("NimbusMonL-Bold.cff");
+ }
+ if (!strcmp("Courier-Oblique", name)) {
+ return get_font_file("NimbusMonL-ReguObli.cff");
+ }
+ if (!strcmp("Courier-BoldOblique", name)) {
+ return get_font_file("NimbusMonL-BoldObli.cff");
+ }
+ if (!strcmp("Helvetica", name)) {
+ return get_font_file("NimbusSanL-Regu.cff");
+ }
+ if (!strcmp("Helvetica-Bold", name)) {
+ return get_font_file("NimbusSanL-Bold.cff");
+ }
+ if (!strcmp("Helvetica-Oblique", name)) {
+ return get_font_file("NimbusSanL-ReguItal.cff");
+ }
+ if (!strcmp("Helvetica-BoldOblique", name)) {
+ return get_font_file("NimbusSanL-BoldItal.cff");
+ }
+ if (!strcmp("Times-Roman", name)) {
+ return get_font_file("NimbusRomNo9L-Regu.cff");
+ }
+ if (!strcmp("Times-Bold", name)) {
+ return get_font_file("NimbusRomNo9L-Medi.cff");
+ }
+ if (!strcmp("Times-Italic", name)) {
+ return get_font_file("NimbusRomNo9L-ReguItal.cff");
+ }
+ if (!strcmp("Times-BoldItalic", name)) {
+ return get_font_file("NimbusRomNo9L-MediItal.cff");
+ }
+ if (!strcmp("Symbol", name)) {
+ return get_font_file("StandardSymL.cff");
+ }
+ if (!strcmp("ZapfDingbats", name)) {
+ return get_font_file("Dingbats.cff");
+ }
+ return NULL;
+}
+
+unsigned char *
+pdf_lookup_substitute_font(int mono, int serif, int bold, int italic, unsigned int *len)
+{
+ if (mono) {
+ if (bold) {
+ if (italic) return pdf_lookup_builtin_font("Courier-BoldOblique", len);
+ else return pdf_lookup_builtin_font("Courier-Bold", len);
+ } else {
+ if (italic) return pdf_lookup_builtin_font("Courier-Oblique", len);
+ else return pdf_lookup_builtin_font("Courier", len);
+ }
+ } else if (serif) {
+ if (bold) {
+ if (italic) return pdf_lookup_builtin_font("Times-BoldItalic", len);
+ else return pdf_lookup_builtin_font("Times-Bold", len);
+ } else {
+ if (italic) return pdf_lookup_builtin_font("Times-Italic", len);
+ else return pdf_lookup_builtin_font("Times-Roman", len);
+ }
+ } else {
+ if (bold) {
+ if (italic) return pdf_lookup_builtin_font("Helvetica-BoldOblique", len);
+ else return pdf_lookup_builtin_font("Helvetica-Bold", len);
+ } else {
+ if (italic) return pdf_lookup_builtin_font("Helvetica-Oblique", len);
+ else return pdf_lookup_builtin_font("Helvetica", len);
+ }
+ }
+}
+
+unsigned char *
+pdf_lookup_substitute_cjk_font(int ros, int serif, unsigned int *len)
+{
+ *len = 0;
+ return get_font_file("droid/DroidSansFallback.ttf");
+}
+
+#endif // NOBUILTINFONT

@ -1,163 +0,0 @@
/*
KindlePDFViewer: MuPDF abstraction for Lua, only image part
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fitz/fitz-internal.h>
#include "blitbuffer.h"
#include "mupdfimg.h"
#include <stdio.h>
#include <stddef.h>
typedef struct Image {
fz_pixmap *pixmap;
fz_context *context;
} Image;
static int newImage(lua_State *L) {
int cache_size = luaL_optint(L, 1, 8 << 20); // 8 MB limit default
Image *img = (Image*) lua_newuserdata(L, sizeof(Image));
img->pixmap = NULL;
luaL_getmetatable(L, "image");
lua_setmetatable(L, -2);
img->context = fz_new_context(NULL, NULL, cache_size);
return 1;
}
static int loadPNGData(lua_State *L) {
Image *img = (Image*) luaL_checkudata(L, 1, "image");
size_t length;
unsigned char *data = luaL_checklstring(L, 2, &length);
fz_try(img->context) {
img->pixmap = fz_load_png(img->context, data, length);
}
fz_catch(img->context) {
return luaL_error(L, "cannot load PNG data");
}
return 0;
}
static int loadJPEGData(lua_State *L) {
Image *img = (Image*) luaL_checkudata(L, 1, "image");
size_t length;
unsigned char *data = luaL_checklstring(L, 2, &length);
fz_try(img->context) {
img->pixmap = fz_load_jpeg(img->context, data, length);
}
fz_catch(img->context) {
return luaL_error(L, "cannot open JPEG data");
}
return 0;
}
static int toBlitBuffer(lua_State *L) {
Image *img = (Image*) luaL_checkudata(L, 1, "image");
BlitBuffer *bb;
int ret;
int w, h;
fz_pixmap *pix;
if(img->pixmap == NULL) {
return luaL_error(L, "no pixmap loaded that we could convert");
}
if(img->pixmap->n == 2) {
pix = img->pixmap;
} else {
fz_try(img->context) {
pix = fz_new_pixmap(img->context, fz_device_gray, img->pixmap->w, img->pixmap->h);
fz_convert_pixmap(img->context, pix, img->pixmap);
}
fz_catch(img->context) {
return luaL_error(L, "can't claim or convert new grayscale fz_pixmap");
}
}
ret = newBlitBufferNative(L, img->pixmap->w, img->pixmap->h, 0, &bb);
if(ret != 1) {
// TODO (?): fail more gracefully, clean up mem?
return ret;
}
uint8_t *bbptr = (uint8_t*)bb->data;
uint16_t *pmptr = (uint16_t*)pix->samples;
int x, y;
for(y = 0; y < bb->h; y++) {
for(x = 0; x < (bb->w / 2); x++) {
bbptr[x] = (((pmptr[x*2 + 1] & 0xF0) >> 4) | (pmptr[x*2] & 0xF0)) ^ 0xFF;
}
if(bb->w & 1) {
bbptr[x] = (pmptr[x*2] & 0xF0) ^ 0xF0;
}
bbptr += bb->pitch;
pmptr += bb->w;
}
if(pix != img->pixmap) {
fz_drop_pixmap(img->context, pix);
}
return 1;
}
static int freeImage(lua_State *L) {
Image *img = (Image*) luaL_checkudata(L, 1, "image");
// should be save if called twice
if(img->pixmap != NULL) {
fz_drop_pixmap(img->context, img->pixmap);
img->pixmap = NULL;
}
if(img->context != NULL) {
fz_free_context(img->context);
img->context = NULL;
}
return 0;
}
static const struct luaL_Reg mupdfimg_func[] = {
{"new", newImage},
{NULL, NULL}
};
static const struct luaL_Reg image_meth[] = {
{"loadPNGData", loadPNGData},
{"loadJPEGData", loadJPEGData},
{"toBlitBuffer", toBlitBuffer},
{"free", freeImage},
{"__gc", freeImage},
{NULL, NULL}
};
int luaopen_mupdfimg(lua_State *L) {
luaL_newmetatable(L, "image");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, image_meth);
lua_pop(L, 1);
luaL_register(L, "mupdfimg", mupdfimg_func);
return 1;
}

@ -1,26 +0,0 @@
/*
KindlePDFViewer: MuPDF abstraction for Lua, only image part
Copyright (C) 2012 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MUPDFIMG_H
#define _MUPDFIMG_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_mupdfimg(lua_State *L);
#endif

825
pdf.c

@ -1,825 +0,0 @@
/*
KindlePDFViewer: MuPDF abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include <pthread.h>
#include <fitz/fitz-internal.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "koptcontext.h"
#include "k2pdfopt.h"
#include "pdf.h"
typedef struct PdfDocument {
fz_document *xref;
fz_context *context;
} PdfDocument;
typedef struct PdfPage {
int num;
#ifdef USE_DISPLAY_LIST
fz_display_list *list;
#endif
fz_page *page;
PdfDocument *doc;
} PdfPage;
static double LOG_TRESHOLD_PERC = 0.05; // 5%
enum {
MAGIC = 0x3795d42b,
};
typedef struct header {
int magic;
size_t sz;
} header;
static size_t msize=0;
static size_t msize_prev;
static size_t msize_max;
static size_t msize_min;
static size_t msize_iniz;
static int is_realloc=0;
#if 0
char* readable_fs(double size/*in bytes*/, char *buf) {
int i = 0;
const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
while (size > 1024) {
size /= 1024;
i++;
}
sprintf(buf, "%.*f %s", i, size, units[i]);
return buf;
}
#endif
static void resetMsize(){
msize_iniz = msize;
msize_prev = 0;
msize_max = 0;
msize_min = (size_t)-1;
}
static void showMsize(){
char buf[15],buf2[15],buf3[15],buf4[15];
//printf("§§§ now: %s was: %s - min: %s - max: %s\n",readable_fs(msize,buf),readable_fs(msize_iniz,buf2),readable_fs(msize_min,buf3),readable_fs(msize_max,buf4));
resetMsize();
}
static void log_size(char *funcName){
if(msize_max < msize)
msize_max = msize;
if(msize_min > msize)
msize_min = msize;
if(1==0 && abs(msize-msize_prev)>msize_prev*LOG_TRESHOLD_PERC){
char buf[15],buf2[15];
//printf("§§§ %s - total: %s (was %s)\n",funcName, readable_fs(msize,buf),readable_fs(msize_prev,buf2));
msize_prev = msize;
}
}
static void *
my_malloc_default(void *opaque, unsigned int size)
{
struct header * h = malloc(size + sizeof(header));
if (h == NULL)
return NULL;
h -> magic = MAGIC;
h -> sz = size;
msize += size + sizeof(struct header);
if(is_realloc!=1)
log_size("alloc");
return (void *)(h + 1);
}
static void
my_free_default(void *opaque, void *ptr)
{
if (ptr != NULL) {
struct header * h = ((struct header *)ptr) - 1;
if (h -> magic != MAGIC) { /* Not allocated by us */
} else {
msize -= h -> sz + sizeof(struct header);
free(h);
}
}
if(is_realloc!=1)
log_size("free");
}
static void *
my_realloc_default(void *opaque, void *old, unsigned int size)
{
void * newp;
if (old==NULL) { //practically, it's a malloc
newp = my_malloc_default(opaque, size);
} else {
struct header * h = ((struct header *)old) - 1;
if (h -> magic != MAGIC) { // Not allocated by my_malloc_default
//printf("§§§ warn: not allocated by my_malloc_default, new size: %i\n",size);
newp = realloc(old,size);
} else { // malloc + free
is_realloc = 1;
size_t oldsize = h -> sz;
//printf("realloc %i -> %i\n",oldsize,size);
newp = my_malloc_default(opaque, size);
if (NULL != newp) {
memcpy(newp, old, oldsize<size?oldsize:size);
my_free_default(opaque, old);
}
log_size("realloc");
is_realloc = 0;
}
}
return(newp);
}
fz_alloc_context my_alloc_default =
{
NULL,
my_malloc_default,
my_realloc_default,
my_free_default
};
static int openDocument(lua_State *L) {
char *filename = strdup(luaL_checkstring(L, 1));
int cache_size = luaL_optint(L, 2, 64 << 20); // 64 MB limit default
char buf[15];
//printf("## cache_size: %s\n",readable_fs(cache_size,buf));
PdfDocument *doc = (PdfDocument*) lua_newuserdata(L, sizeof(PdfDocument));
luaL_getmetatable(L, "pdfdocument");
lua_setmetatable(L, -2);
doc->context = fz_new_context(&my_alloc_default, NULL, cache_size);
fz_try(doc->context) {
doc->xref = fz_open_document(doc->context, filename);
}
fz_catch(doc->context) {
free(filename);
return luaL_error(L, "cannot open PDF file");
}
free(filename);
return 1;
}
static int needsPassword(lua_State *L) {
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument");
lua_pushboolean(L, fz_needs_password(doc->xref));
return 1;
}
static int authenticatePassword(lua_State *L) {
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument");
char *password = strdup(luaL_checkstring(L, 2));
if (!fz_authenticate_password(doc->xref, password)) {
lua_pushboolean(L, 0);
} else {
lua_pushboolean(L, 1);
}
free(password);
return 1;
}
static int closeDocument(lua_State *L) {
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument");
// should be save if called twice
if(doc->xref != NULL) {
fz_close_document(doc->xref);
doc->xref = NULL;
}
if(doc->context != NULL) {
fz_free_context(doc->context);
doc->context = NULL;
}
return 0;
}
static int getNumberOfPages(lua_State *L) {
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument");
fz_try(doc->context) {
lua_pushinteger(L, fz_count_pages(doc->xref));
}
fz_catch(doc->context) {
return luaL_error(L, "cannot access page tree");
}
return 1;
}
/*
* helper function for getTableOfContent()
*/
static int walkTableOfContent(lua_State *L, fz_outline* ol, int *count, int depth) {
depth++;
while(ol) {
lua_pushnumber(L, *count);
/* set subtable */
lua_newtable(L);
lua_pushstring(L, "page");
lua_pushnumber(L, ol->dest.ld.gotor.page + 1);
lua_settable(L, -3);
lua_pushstring(L, "depth");
lua_pushnumber(L, depth);
lua_settable(L, -3);
lua_pushstring(L, "title");
lua_pushstring(L, ol->title);
lua_settable(L, -3);
lua_settable(L, -3);
(*count)++;
if (ol->down) {
walkTableOfContent(L, ol->down, count, depth);
}
ol = ol->next;
}
return 0;
}
/*
* Return a table like this:
* {
* {page=12, depth=1, title="chapter1"},
* {page=54, depth=1, title="chapter2"},
* }
*/
static int getTableOfContent(lua_State *L) {
fz_outline *ol;
int count = 1;
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument");
ol = fz_load_outline(doc->xref);
lua_newtable(L);
walkTableOfContent(L, ol, &count, 0);
return 1;
}
static int openPage(lua_State *L) {
fz_device *dev;
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument");
int pageno = luaL_checkint(L, 2);
fz_try(doc->context) {
if(pageno < 1 || pageno > fz_count_pages(doc->xref)) {
return luaL_error(L, "cannot open page #%d, out of range (1-%d)",
pageno, fz_count_pages(doc->xref));
}
PdfPage *page = (PdfPage*) lua_newuserdata(L, sizeof(PdfPage));
luaL_getmetatable(L, "pdfpage");
lua_setmetatable(L, -2);
page->page = fz_load_page(doc->xref, pageno - 1);
page->doc = doc;
}
fz_catch(doc->context) {
return luaL_error(L, "cannot open page #%d", pageno);
}
showMsize();
return 1;
}
static void load_lua_text_page(lua_State *L, fz_text_page *page)
{
fz_text_block *block;
fz_text_line *aline;
fz_text_span *span;
fz_rect bbox, linebbox;
int i;
int word, line;
int len, c;
int start;
char chars[4]; // max length of UTF-8 encoded rune
luaL_Buffer textbuf;
/* table that contains all the lines */
lua_newtable(L);
line = 1;
for (block = page->blocks; block < page->blocks + page->len; block++)
{
for (aline = block->lines; aline < block->lines + block->len; aline++)
{
linebbox = fz_empty_rect;
/* will hold information about a line: */
lua_newtable(L);
word = 1;
for (span = aline->spans; span < aline->spans + aline->len; span++)
{
for(i = 0; i < span->len; ) {
/* will hold information about a word: */
lua_newtable(L);
luaL_buffinit(L, &textbuf);
bbox = span->text[i].bbox; // start with sensible default
for(; i < span->len; i++) {
/* check for space characters */
if(span->text[i].c == ' ' ||
span->text[i].c == '\t' ||
span->text[i].c == '\n' ||
span->text[i].c == '\v' ||
span->text[i].c == '\f' ||
span->text[i].c == '\r' ||
span->text[i].c == 0xA0 ||
span->text[i].c == 0x1680 ||
span->text[i].c == 0x180E ||
(span->text[i].c >= 0x2000 && span->text[i].c <= 0x200A) ||
span->text[i].c == 0x202F ||
span->text[i].c == 0x205F ||
span->text[i].c == 0x3000) {
// ignore and end word
i++;
break;
}
len = fz_runetochar(chars, span->text[i].c);
for(c = 0; c < len; c++) {
luaL_addchar(&textbuf, chars[c]);
}
bbox = fz_union_rect(bbox, span->text[i].bbox);
linebbox = fz_union_rect(linebbox, span->text[i].bbox);
}
lua_pushstring(L, "word");
luaL_pushresult(&textbuf);
lua_settable(L, -3);
/* bbox for a word: */
lua_pushstring(L, "x0");
lua_pushinteger(L, bbox.x0);
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushinteger(L, bbox.y0);
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushinteger(L, bbox.x1);
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushinteger(L, bbox.y1);
lua_settable(L, -3);
lua_rawseti(L, -2, word++);
}
}
/* bbox for a whole line */
lua_pushstring(L, "x0");
lua_pushinteger(L, linebbox.x0);
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushinteger(L, linebbox.y0);
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushinteger(L, linebbox.x1);
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushinteger(L, linebbox.y1);
lua_settable(L, -3);
lua_rawseti(L, -2, line++);
}
}
}
/* get the text of the given page
*
* will return text in a Lua table that is modeled after
* djvu.c creates this table.
*
* note that the definition of "line" is somewhat arbitrary
* here (for now)
*
* MuPDFs API provides text as single char information
* that is collected in "spans". we use a span as a "line"
* in Lua output and segment spans into words by looking
* for space characters.
*
* will return an empty table if we have no text
*/
static int getPageText(lua_State *L) {
fz_text_page *text_page;
fz_text_sheet *text_sheet;
fz_device *tdev;
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
text_page = fz_new_text_page(page->doc->context, fz_bound_page(page->doc->xref, page->page));
text_sheet = fz_new_text_sheet(page->doc->context);
tdev = fz_new_text_device(page->doc->context, text_sheet, text_page);
fz_run_page(page->doc->xref, page->page, tdev, fz_identity, NULL);
fz_free_device(tdev);
tdev = NULL;
load_lua_text_page(L, text_page);
fz_free_text_page(page->doc->context, text_page);
fz_free_text_sheet(page->doc->context, text_sheet);
return 1;
}
static int getPageSize(lua_State *L) {
fz_matrix ctm;
fz_rect bounds;
fz_rect bbox;
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
bounds = fz_bound_page(page->doc->xref, page->page);
ctm = fz_scale(dc->zoom, dc->zoom) ;
ctm = fz_concat(ctm, fz_rotate(dc->rotate));
bbox = fz_transform_rect(ctm, bounds);
lua_pushnumber(L, bbox.x1-bbox.x0);
lua_pushnumber(L, bbox.y1-bbox.y0);
return 2;
}
static int getUsedBBox(lua_State *L) {
fz_bbox result;
fz_matrix ctm;
fz_device *dev;
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
/* returned BBox is in centi-point (n * 0.01 pt) */
ctm = fz_scale(100, 100);
fz_try(page->doc->context) {
dev = fz_new_bbox_device(page->doc->context, &result);
fz_run_page(page->doc->xref, page->page, dev, ctm, NULL);
}
fz_always(page->doc->context) {
fz_free_device(dev);
}
fz_catch(page->doc->context) {
return luaL_error(L, "cannot calculate bbox for page");
}
lua_pushnumber(L, ((double)result.x0)/100);
lua_pushnumber(L, ((double)result.y0)/100);
lua_pushnumber(L, ((double)result.x1)/100);
lua_pushnumber(L, ((double)result.y1)/100);
return 4;
}
static int closePage(lua_State *L) {
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
if(page->page != NULL) {
fz_free_page(page->doc->xref, page->page);
page->page = NULL;
}
return 0;
}
/* bmpmupdf.c from willuslib */
static int bmpmupdf_pixmap_to_bmp(WILLUSBITMAP *bmp, fz_context *ctx, fz_pixmap *pixmap) {
unsigned char *p;
int ncomp, i, row, col;
bmp->width = fz_pixmap_width(ctx, pixmap);
bmp->height = fz_pixmap_height(ctx, pixmap);
ncomp = fz_pixmap_components(ctx, pixmap);
/* Has to be 8-bit or RGB */
if (ncomp != 2 && ncomp != 4)
return (-1);
bmp->bpp = (ncomp == 2) ? 8 : 24;
bmp_alloc(bmp);
if (ncomp == 2)
for (i = 0; i < 256; i++)
bmp->red[i] = bmp->green[i] = bmp->blue[i] = i;
p = fz_pixmap_samples(ctx, pixmap);
if (ncomp == 1)
for (row = 0; row < bmp->height; row++) {
unsigned char *dest;
dest = bmp_rowptr_from_top(bmp, row);
memcpy(dest, p, bmp->width);
p += bmp->width;
}
else if (ncomp == 2)
for (row = 0; row < bmp->height; row++) {
unsigned char *dest;
dest = bmp_rowptr_from_top(bmp, row);
for (col = 0; col < bmp->width; col++, dest++, p += 2)
dest[0] = p[0];
}
else
for (row = 0; row < bmp->height; row++) {
unsigned char *dest;
dest = bmp_rowptr_from_top(bmp, row);
for (col = 0; col < bmp->width;
col++, dest += ncomp - 1, p += ncomp)
memcpy(dest, p, ncomp - 1);
}
return (0);
}
static int reflowPage(lua_State *L) {
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
KOPTContext *kctx = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
fz_device *dev;
fz_pixmap *pix;
fz_rect bounds,bounds2;
fz_matrix ctm;
fz_bbox bbox;
pix = NULL;
fz_var(pix);
bounds.x0 = kctx->bbox.x0;
bounds.y0 = kctx->bbox.y0;
bounds.x1 = kctx->bbox.x1;
bounds.y1 = kctx->bbox.y1;
double dpp,zoom;
zoom = kctx->zoom;
double dpi = 250*zoom*kctx->quality;
do {
dpp = dpi / 72.;
ctm = fz_scale(dpp, dpp);
// ctm=fz_concat(ctm,fz_rotate(rotation));
bounds2 = fz_transform_rect(ctm, bounds);
bbox = fz_round_rect(bounds2);
printf("reading page:%d,%d,%d,%d zoom:%.2f dpi:%.0f\n",bbox.x0,bbox.y0,bbox.x1,bbox.y1,zoom,dpi);
kctx->zoom = zoom;
zoom *= kctx->shrink_factor;
dpi *= kctx->shrink_factor;
} while (bbox.x1 > kctx->read_max_width | bbox.y1 > kctx->read_max_height);
pix = fz_new_pixmap_with_bbox(page->doc->context, fz_device_gray, bbox);
fz_clear_pixmap_with_value(page->doc->context, pix, 0xff);
dev = fz_new_draw_device(page->doc->context, pix);
#ifdef MUPDF_TRACE
fz_device *tdev;
fz_try(page->doc->context) {
tdev = fz_new_trace_device(page->doc->context);
fz_run_page(page->doc->xref, page->page, tdev, ctm, NULL);
}
fz_always(page->doc->context) {
fz_free_device(tdev);
}
#endif
fz_run_page(page->doc->xref, page->page, dev, ctm, NULL);
fz_free_device(dev);
WILLUSBITMAP *src = malloc(sizeof(WILLUSBITMAP));
bmp_init(src);
int status = bmpmupdf_pixmap_to_bmp(src, page->doc->context, pix);
fz_drop_pixmap(page->doc->context, pix);
kctx->src = src;
if (kctx->precache) {
pthread_t rf_thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create( &rf_thread, &attr, k2pdfopt_reflow_bmp, (void*) kctx);
pthread_attr_destroy(&attr);
} else {
k2pdfopt_reflow_bmp(kctx);
}
return 0;
}
static int drawReflowedPage(lua_State *L) {
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
uint8_t *koptr = kc->data;
uint8_t *bbptr = bb->data;
int x_offset = 0;
int y_offset = 0;
bbptr += bb->pitch * y_offset;
int x, y;
for(y = y_offset; y < bb->h; y++) {
for(x = x_offset/2; x < (bb->w/2); x++) {
int p = x*2 - x_offset;
bbptr[x] = (((koptr[p + 1] & 0xF0) >> 4) | (koptr[p] & 0xF0)) ^ 0xFF;
}
bbptr += bb->pitch;
koptr += bb->w;
if (bb->w & 1) {
bbptr[x] = 255 - (koptr[x*2] & 0xF0);
}
}
return 0;
}
static int drawPage(lua_State *L) {
fz_pixmap *pix;
fz_device *dev;
fz_matrix ctm;
fz_bbox bbox;
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
bbox.x0 = luaL_checkint(L, 4);
bbox.y0 = luaL_checkint(L, 5);
bbox.x1 = bbox.x0 + bb->w;
bbox.y1 = bbox.y0 + bb->h;
pix = fz_new_pixmap_with_bbox(page->doc->context, fz_device_gray, bbox);
fz_clear_pixmap_with_value(page->doc->context, pix, 0xff);
ctm = fz_scale(dc->zoom, dc->zoom);
ctm = fz_concat(ctm, fz_rotate(dc->rotate));
ctm = fz_concat(ctm, fz_translate(dc->offset_x, dc->offset_y));
dev = fz_new_draw_device(page->doc->context, pix);
#ifdef MUPDF_TRACE
fz_device *tdev;
fz_try(page->doc->context) {
tdev = fz_new_trace_device(page->doc->context);
fz_run_page(page->doc->xref, page->page, tdev, ctm, NULL);
}
fz_always(page->doc->context) {
fz_free_device(tdev);
}
#endif
fz_run_page(page->doc->xref, page->page, dev, ctm, NULL);
fz_free_device(dev);
if(dc->gamma >= 0.0) {
fz_gamma_pixmap(page->doc->context, pix, dc->gamma);
}
uint8_t *bbptr = (uint8_t*)bb->data;
uint16_t *pmptr = (uint16_t*)pix->samples;
int x, y;
for(y = 0; y < bb->h; y++) {
for(x = 0; x < (bb->w / 2); x++) {
bbptr[x] = (((pmptr[x*2 + 1] & 0xF0) >> 4) | (pmptr[x*2] & 0xF0)) ^ 0xFF;
}
if(bb->w & 1) {
bbptr[x] = (pmptr[x*2] & 0xF0) ^ 0xF0;
}
bbptr += bb->pitch;
pmptr += bb->w;
}
fz_drop_pixmap(page->doc->context, pix);
return 0;
}
static int getCacheSize(lua_State *L) {
//printf("## mupdf getCacheSize = %zu\n", msize);
lua_pushnumber(L, msize);
return 1;
}
static int cleanCache(lua_State *L) {
//printf("## mupdf cleanCache NOP\n");
return 0;
}
static int getPageLinks(lua_State *L) {
fz_link *page_links;
fz_link *link;
int link_count;
PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage");
page_links = fz_load_links(page->doc->xref, page->page); // page->doc->xref?
lua_newtable(L); // all links
link_count = 0;
for (link = page_links; link; link = link->next) {
lua_newtable(L); // new link
lua_pushstring(L, "x0");
lua_pushinteger(L, link->rect.x0);
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushinteger(L, link->rect.y0);
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushinteger(L, link->rect.x1);
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushinteger(L, link->rect.y1);
lua_settable(L, -3);
if (link->dest.kind == FZ_LINK_URI) {
lua_pushstring(L, "uri");
lua_pushstring(L, link->dest.ld.uri.uri);
lua_settable(L, -3);
} else if (link->dest.kind == FZ_LINK_GOTO) {
lua_pushstring(L, "page");
lua_pushinteger(L, link->dest.ld.gotor.page); // FIXME page+1?
lua_settable(L, -3);
} else {
printf("ERROR: unkown link kind: %x", link->dest.kind);
}
lua_rawseti(L, -2, ++link_count);
}
//printf("## getPageLinks found %d links in document\n", link_count);
fz_drop_link(page->doc->context, page_links);
return 1;
}
static const struct luaL_Reg pdf_func[] = {
{"openDocument", openDocument},
{NULL, NULL}
};
static const struct luaL_Reg pdfdocument_meth[] = {
{"needsPassword", needsPassword},
{"authenticatePassword", authenticatePassword},
{"openPage", openPage},
{"getPages", getNumberOfPages},
{"getToc", getTableOfContent},
{"close", closeDocument},
{"getCacheSize", getCacheSize},
{"cleanCache", cleanCache},
{"__gc", closeDocument},
{NULL, NULL}
};
static const struct luaL_Reg pdfpage_meth[] = {
{"getSize", getPageSize},
{"getUsedBBox", getUsedBBox},
{"getPageText", getPageText},
{"getPageLinks", getPageLinks},
{"close", closePage},
{"__gc", closePage},
{"reflow", reflowPage},
{"rfdraw", drawReflowedPage},
{"draw", drawPage},
{NULL, NULL}
};
int luaopen_pdf(lua_State *L) {
luaL_newmetatable(L, "pdfdocument");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, pdfdocument_meth);
lua_pop(L, 1);
luaL_newmetatable(L, "pdfpage");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, pdfpage_meth);
lua_pop(L, 1);
luaL_register(L, "pdf", pdf_func);
return 1;
}

26
pdf.h

@ -1,26 +0,0 @@
/*
KindlePDFViewer: MuPDF abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PDF_H
#define _PDF_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_pdf(lua_State *L);
#endif

280
pic.c

@ -1,280 +0,0 @@
/*
KindlePDFViewer: Picture viewer abstraction for Lua
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "blitbuffer.h"
#include "drawcontext.h"
#include "pic.h"
#include "pic_jpeg.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
typedef struct PicDocument {
int width;
int height;
int components;
uint8_t *image;
} PicDocument;
typedef struct PicPage {
int width;
int height;
uint8_t *image;
PicDocument *doc;
} PicPage;
/* Uses luminance match for approximating the human perception of colour,
* as per http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
* L = 0.299*Red + 0.587*Green + 0.114*Blue */
static uint8_t *rgbToGrayscale(uint8_t *image, int width, int height)
{
int x, y;
uint8_t *buf = malloc(width*height+1);
if (!buf) return NULL;
for (x=0; x<width; x++)
for (y=0; y<height; y++) {
int pos = 3*(x+y*width);
buf[x+y*width] = (uint8_t)(0.299*((double)image[pos]) + 0.587*((double)image[pos+1]) + 0.114*((double)image[pos+2]));
}
return buf;
}
static int openDocument(lua_State *L) {
int width, height, components;
const char *filename = luaL_checkstring(L, 1);
PicDocument *doc = (PicDocument*) lua_newuserdata(L, sizeof(PicDocument));
luaL_getmetatable(L, "picdocument");
lua_setmetatable(L, -2);
uint8_t *raw_image = jpegLoadFile(filename, &width, &height, &components);
if (!raw_image)
return luaL_error(L, "Cannot open jpeg file");
doc->image = NULL;
if (components == 1)
doc->image = raw_image;
else if (components == 3) {
uint8_t *gray_image = rgbToGrayscale(raw_image, width, height);
free(raw_image);
if (!gray_image)
return luaL_error(L, "Cannot convert to grayscale");
else
doc->image = gray_image;
} else {
free(raw_image);
return luaL_error(L, "Unsupported image format");
}
doc->width = width;
doc->height = height;
doc->components = components;
return 1;
}
static int openPage(lua_State *L) {
PicDocument *doc = (PicDocument*) luaL_checkudata(L, 1, "picdocument");
PicPage *page = (PicPage*) lua_newuserdata(L, sizeof(PicPage));
luaL_getmetatable(L, "picpage");
lua_setmetatable(L, -2);
page->width = doc->width;
page->height = doc->height;
page->image = doc->image;
page->doc = doc;
return 1;
}
static int getNumberOfPages(lua_State *L) {
lua_pushinteger(L, 1);
return 1;
}
static int getOriginalPageSize(lua_State *L) {
PicDocument *doc = (PicDocument*) luaL_checkudata(L, 1, "picdocument");
lua_pushnumber(L, doc->width);
lua_pushnumber(L, doc->height);
lua_pushnumber(L, doc->components);
return 3;
}
/* re-entrant */
static int closeDocument(lua_State *L) {
PicDocument *doc = (PicDocument*) luaL_checkudata(L, 1, "picdocument");
if (doc->image != NULL) {
free(doc->image);
doc->image = NULL;
}
return 0;
}
/* uses very simple nearest neighbour scaling */
static void scaleImage(uint8_t *result, uint8_t *image, int width, int height, int new_width, int new_height)
{
int x, y;
for (x=0; x<new_width; x++)
for (y=0; y<new_height; y++)
result[x+y*new_width] = image[(x*width/new_width) + (y*height/new_height)*width];
}
static int drawPage(lua_State *L) {
PicPage *page = (PicPage*) luaL_checkudata(L, 1, "picpage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer");
int x_offset = MAX(0, dc->offset_x);
int y_offset = MAX(0, dc->offset_y);
int x, y;
int img_width = page->width;
int img_height = page->height;
int img_new_width = bb->w;
int img_new_height = bb->h;
unsigned char adjusted_low[16], adjusted_high[16];
int i, adjust_pixels = 0;
/* prepare the tables for adjusting the intensity of pixels */
if (dc->gamma != -1.0) {
for (i=0; i<16; i++) {
adjusted_low[i] = MIN(15, (unsigned char)floorf(dc->gamma * (float)i));
adjusted_high[i] = adjusted_low[i] << 4;
}
adjust_pixels = 1;
}
uint8_t *scaled_image = malloc(img_new_width*img_new_height+1);
if (!scaled_image)
return 0;
scaleImage(scaled_image, page->image, img_width, img_height, img_new_width, img_new_height);
uint8_t *bbptr = bb->data;
uint8_t *pmptr = scaled_image;
bbptr += bb->pitch * y_offset;
for(y = y_offset; y < img_new_height; y++) {
for(x = x_offset/2; x < (img_new_width / 2); x++) {
int p = x*2 - x_offset;
unsigned char low = 15 - (pmptr[p + 1] >> 4);
unsigned char high = 15 - (pmptr[p] >> 4);
if (adjust_pixels)
bbptr[x] = adjusted_high[high] | adjusted_low[low];
else
bbptr[x] = (high << 4) | low;
}
if (img_new_width & 1)
bbptr[x] = 255 - (pmptr[x*2] & 0xF0);
bbptr += bb->pitch;
pmptr += img_new_width;
}
free(scaled_image);
return 0;
}
static int getCacheSize(lua_State *L) {
lua_pushnumber(L, 0);
return 1;
}
static int cleanCache(lua_State *L) {
return 0;
}
static int getPageSize(lua_State *L) {
PicPage *page = (PicPage*) luaL_checkudata(L, 1, "picpage");
DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext");
lua_pushnumber(L, dc->zoom * page->width);
lua_pushnumber(L, dc->zoom * page->height);
return 2;
}
static int closePage(lua_State *L) {
return 0;
}
/* unsupported so fake it */
static int getUsedBBox(lua_State *L) {
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)0.01);
lua_pushnumber(L, (double)-0.01);
lua_pushnumber(L, (double)-0.01);
return 4;
}
static int getTableOfContent(lua_State *L) {
lua_newtable(L);
return 1;
}
static const struct luaL_Reg pic_func[] = {
{"openDocument", openDocument},
{NULL, NULL}
};
static const struct luaL_Reg picdocument_meth[] = {
{"openPage", openPage},
{"getPages", getNumberOfPages},
{"getToc", getTableOfContent},
{"getOriginalPageSize", getOriginalPageSize},
{"getCacheSize", getCacheSize},
{"close", closeDocument},
{"cleanCache", cleanCache},
{"__gc", closeDocument},
{NULL, NULL}
};
static const struct luaL_Reg picpage_meth[] = {
{"getSize", getPageSize},
{"getUsedBBox", getUsedBBox},
{"close", closePage},
{"__gc", closePage},
{"draw", drawPage},
{NULL, NULL}
};
int luaopen_pic(lua_State *L) {
luaL_newmetatable(L, "picdocument");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, picdocument_meth);
lua_pop(L, 1);
luaL_newmetatable(L, "picpage");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
luaL_register(L, NULL, picpage_meth);
lua_pop(L, 1);
luaL_register(L, "pic", pic_func);
return 1;
}

27
pic.h

@ -1,27 +0,0 @@
/*
KindlePDFViewer: JPEG Picture viewer abstraction for Lua
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PIC_H
#define _PIC_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_pic(lua_State *L);
#endif

@ -1,84 +0,0 @@
/*
KindlePDFViewer: JPEG support for Picture Viewer module
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include <setjmp.h>
#include <stdio.h>
#include "jpeglib.h"
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr *my_error_ptr;
METHODDEF(void) my_error_exit(j_common_ptr cinfo)
{
my_error_ptr myerr = (my_error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
uint8_t *jpegLoadFile(const char *fname, int *width, int *height, int *components)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *infile;
JSAMPARRAY buffer;
int row_stride;
long cont;
JSAMPLE *image_buffer;
if ((infile = fopen(fname, "r")) == NULL) return NULL;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return NULL;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
(void) jpeg_read_header(&cinfo, TRUE);
(void) jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
image_buffer = (JSAMPLE *) malloc(cinfo.image_width*cinfo.image_height*cinfo.output_components);
if (image_buffer == NULL) return NULL;
*width = cinfo.image_width;
*height = cinfo.image_height;
//cont = cinfo.output_height - 1;
cont = 0;
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(image_buffer + cinfo.image_width * cinfo.output_components * cont, buffer[0], row_stride);
cont++;
}
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
*components = cinfo.output_components;
return (uint8_t *)image_buffer;
}

@ -1,30 +0,0 @@
/*
KindlePDFViewer: Interface to JPEG module for picture viewer
Copyright (C) 2012 Tigran Aivazian <tigran@bibles.org.uk>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PIC_JPEG_H
#define _PIC_JPEG_H
/* each new image format must provide fmtLoadFile() function which
* performs the following:
* 1. Opens the file 'filename'
* 2. Reads the image data from it into a buffer allocated with malloc()
* 3. Fills in the image *width, *height and *components (number of bytes per pixel)
* 4. Closes the file
* 5. Returns the pointer to the image data
*/
extern uint8_t *jpegLoadFile(const char *fname, int *width, int *height, int *components);
#endif

@ -1,114 +0,0 @@
/*
KindlePDFViewer: power slider key event watcher
Copyright (C) 2012 Qingping Hou <dave2008713@gamil.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "popen-noshell/popen_noshell.h"
#include <err.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
int
main ( int argc, char *argv[] )
{
int fd;
FILE *fp;
char std_out[256];
int status;
struct popen_noshell_pass_to_pclose pclose_arg;
struct input_event ev;
__u16 key_code = 10000;
/* create the npipe if not exists */
/*if(access(argv[1], F_OK)){*/
/*printf("npipe %s not found, try to create it...\n", argv[1]);*/
/*if(mkfifo(argv[1], 0777)) {*/
/*printf("Create npipe %s failed!\n", argv[1]);*/
/*}*/
/*}*/
/* open npipe for writing */
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if(fd < 0) {
printf("Open %s failed: %s\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
/* initialize event struct */
ev.type = EV_KEY;
ev.code = key_code;
ev.value = 1;
/* listen power slider events */
char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver", (char *) NULL};
fp = popen_noshell("lipc-wait-event", (const char * const *)chargv, "r", &pclose_arg, 0);
if (!fp) {
err(EXIT_FAILURE, "popen_noshell()");
}
while(fgets(std_out, sizeof(std_out)-1, fp)) {
/* printf("Got line: %s", std_out); */
if(std_out[0] == 'g') {
ev.code = CODE_IN_SAVER;
} else if(std_out[0] == 'o') {
ev.code = CODE_OUT_SAVER;
} else {
printf("Unrecognized event.\n");
exit(EXIT_FAILURE);
}
/* fill event struct */
gettimeofday(&ev.time, NULL);
/* printf("Send event %d\n", ev.code); */
/* generate event */
if(write(fd, &ev, sizeof(struct input_event)) == -1) {
printf("Failed to generate event.\n");
}
}
status = pclose_noshell(&pclose_arg);
if (status == -1) {
err(EXIT_FAILURE, "pclose_noshell()");
} else {
printf("Power slider event listener child exited with status %d.\n", status);
if WIFEXITED(status) {
printf("Child exited normally with status: %d.\n", WEXITSTATUS(status));
}
if WIFSIGNALED(status) {
printf("Child terminated by signal: %d.\n", WTERMSIG(status));
}
}
close(fd);
return EXIT_SUCCESS;
}

@ -1,94 +0,0 @@
/*
KindlePDFViewer: miscellaneous utility functions for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/time.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include "util.h"
static int gettime(lua_State *L) {
struct timeval tv;
gettimeofday(&tv, NULL);
lua_pushinteger(L, tv.tv_sec);
lua_pushinteger(L, tv.tv_usec);
return 2;
}
static int util_sleep(lua_State *L) {
unsigned int seconds = luaL_optint(L, 1, 0);
sleep(seconds);
return 0;
}
static int util_usleep(lua_State *L) {
useconds_t useconds = luaL_optint(L, 1, 0);
usleep(useconds);
return 0;
}
static int util_df(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
struct statvfs vfs;
statvfs(path, &vfs);
lua_pushnumber(L, (double)vfs.f_bfree * (double)vfs.f_bsize);
return 1;
}
/* Turn UTF-8 char code to Unicode */
static int utf8charcode(lua_State *L) {
size_t len;
const char *utf8char = luaL_checklstring(L, 1, &len);
int c;
if(len == 1) {
c = utf8char[0] & 0x7F; /* should not be needed */
} else if(len == 2) {
c = ((utf8char[0] & 0x1F) << 6) | (utf8char[1] & 0x3F);
} else if(len == 3) {
c = ((utf8char[0] & 0x0F) << 12) | ((utf8char[1] & 0x3F) << 6) | (utf8char[2] & 0x3F);
} else {
// 4, 5, 6 byte cases still missing
return 0;
}
lua_pushinteger(L, c);
return 1;
}
static int isEmulated(lua_State *L) {
#ifdef EMULATE_READER
lua_pushinteger(L, 1);
#else
lua_pushinteger(L, 0);
#endif
return 1;
}
static const struct luaL_Reg util_func[] = {
{"gettime", gettime},
{"sleep", util_sleep},
{"usleep", util_usleep},
{"utf8charcode", utf8charcode},
{"isEmulated", isEmulated},
{"df", util_df},
{NULL, NULL}
};
int luaopen_util(lua_State *L) {
luaL_register(L, "util", util_func);
return 1;
}

@ -1,27 +0,0 @@
/*
KindlePDFViewer: miscellaneous utility functions for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _UTIL_H
#define _UTIL_H
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int luaopen_util(lua_State *L);
#endif
Loading…
Cancel
Save