mirror of https://github.com/koreader/koreader
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
parent
8ff9a1a98d
commit
364bf96f7a
@ -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;
|
||||
}
|
@ -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
|
@ -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"])
|
||||
)
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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…
Reference in New Issue