Ejemplo n.º 1
0
static unsigned char *bmp_dataptr(WILLUSBITMAP *bmap,int px,int py)

    {
    if (bmap->type==WILLUSBITMAP_TYPE_NATIVE)
        return(&bmap->data[(bmap->height-1-py)*bmp_bytewidth(bmap)+px*3]);
    return(&bmap->data[py*bmp_bytewidth(bmap)+px*3]);
    }
Ejemplo n.º 2
0
static int getPagePix(lua_State *L) {
	DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
	KOPTContext *kctx = (KOPTContext*) lua_topointer(L, 2);
	ddjvu_rect_t prect;
	ddjvu_rect_t rrect;
	int px, py, pw, ph, rx, ry, rw, rh, status;

	px = 0;
    py = 0;
    pw = ddjvu_page_get_width(page->page_ref);
    ph = ddjvu_page_get_height(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);

    float scale = kctx->zoom;

    prect.w = pw * scale;
    prect.h = ph * scale;
    rrect.x = rx * scale;
    rrect.y = ry * scale;
    rrect.w = rw * scale;
    rrect.h = rh * scale;
    printf("rendering page:%d,%d,%d,%d\n",rrect.x,rrect.y,rrect.w,rrect.h);

	WILLUSBITMAP *dst = &kctx->src;
	bmp_init(dst);
	dst->width = rrect.w;
	dst->height = rrect.h;
	dst->bpp = 8;
	bmp_alloc(dst);
	if (dst->bpp == 8) {
		int ii;
		for (ii = 0; ii < 256; ii++)
		dst->red[ii] = dst->blue[ii] = dst->green[ii] = ii;
	}

	ddjvu_format_set_row_order(page->doc->pixelformat, 1);
	ddjvu_page_render(page->page_ref, 0, &prect, &rrect, page->doc->pixelformat,
		bmp_bytewidth(dst), (char *) dst->data);

	return 0;
}
Ejemplo n.º 3
0
double bmp_inflections_horizontal(WILLUSBITMAP *srcgrey,int ndivisions,int delta,int *wthresh)

    {
    int x0,x1,nx,bw,i,nh,nisum,ni,wt,wtmax;
    double *g;
    char *funcname="bmp_inflections_vertical";

    nh=srcgrey->height/ndivisions;
    x0=srcgrey->width/6;
    x1=srcgrey->width-x0;
    nx=x1-x0;
    bw=bmp_bytewidth(srcgrey);
    willus_dmem_alloc_warn(22,(void **)&g,nx*sizeof(double),funcname,10);
    wtmax=-1;
    for (nisum=0,i=0;i<10;i++)
        {
        int y0,y1,ny,j;

        y0=(srcgrey->height-nh)*(i+2)/13;
        y1=y0+nh;
        if (y1>srcgrey->height)
            y1=srcgrey->height;
        ny=y1-y0; 
        for (j=x0;j<x1;j++)
            {
            int k,rsum;
            unsigned char *p;

            p=bmp_rowptr_from_top(srcgrey,y0)+j;
            for (rsum=k=0;k<ny;k++,p+=bw)
                rsum+=p[0];
            g[j-x0]=(double)rsum/ny;
            }
        wt=(*wthresh);
        ni=inflection_count(g,nx,delta,&wt);
        if ((*wthresh)<0 && ni>=3 && wt>wtmax)
            wtmax=wt;
        if (ni>nisum)
            nisum=ni;
        }
    willus_dmem_free(22,&g,funcname);
    if ((*wthresh)<0)
        (*wthresh)=wtmax;
    return(nisum);
    }
Ejemplo n.º 4
0
/*
** Get the contents of the specified window handle and put
** them into the specified bitmap.  x0,y0 = upper left coordinates
** of source rectangle.
*/
int bmp_get_bmp(WILLUSBITMAP *bmp,void *handle,int x0,int y0)

    {
    HWND    h;
    HDC     hDC,memDC;
    BITMAPINFO         *bmi;
    static  HBITMAP hBitmap=NULL;
    int     i,bytewidth;
    int     planes,bpp;
    /* Worst case size (8-bit w/palette) */
    static char _bmih[sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)];
    /*
    RECT    winsize;
    */

    h=(HWND)handle;
    /*
    h=GetDesktopWindow();
    GetWindowRect(h,&winsize);
    winwidth = winsize.right-winsize.left;
    winheight = winsize.bottom-winsize.top;
    */
    /* Get device context */
    hDC=GetDC(h);
    if (hDC==NULL)
        return(4);

    /*
    ** Allocate bit map info structure (has to be allocated due to
    ** arbitrarily sized color palette ==> cannot be statically declared)
    */
    bmi=(BITMAPINFO *)_bmih;
    bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi->bmiHeader.biWidth = bmp->width;
    bmi->bmiHeader.biHeight = bmp->height;
    bmi->bmiHeader.biPlanes = 1;
    bmi->bmiHeader.biBitCount = bmp->bpp;
    bmi->bmiHeader.biCompression = BI_RGB;
    bmi->bmiHeader.biSizeImage = bmp->width*bmp->height*(bmp->bpp==8 ? 1 : 3);
    bmi->bmiHeader.biXPelsPerMeter = 72;
    bmi->bmiHeader.biYPelsPerMeter = 72;
    bmi->bmiHeader.biClrUsed = 0;
    bmi->bmiHeader.biClrImportant = 0;

    planes=GetDeviceCaps(hDC,PLANES);
    bpp=GetDeviceCaps(hDC,BITSPIXEL);
    /* Create bitmap buffer */
    hBitmap=CreateBitmap(bmp->width,
                         bmp->type==WILLUSBITMAP_TYPE_WIN32 ? bmp->height : 1,
                         planes,bpp,NULL);
    if (hBitmap==NULL)
        {
        ReleaseDC(h,hDC);
        return(5);
        }
    memDC = CreateCompatibleDC(hDC);
    SelectObject(memDC,hBitmap);
    if (bmp->type == WILLUSBITMAP_TYPE_WIN32)
        {
        /* Get the whole enchilida */
        BitBlt(memDC,0,0,bmp->width,bmp->height,hDC,x0,y0,SRCCOPY);
        GetDIBits(memDC,hBitmap,0,bmp->height,bmp->data,bmi,DIB_RGB_COLORS);
        }
    else
        {
        bytewidth = bmp_bytewidth(bmp);

        /* Just one scan line at a time */
        bmi->bmiHeader.biHeight = 1;
        bmi->bmiHeader.biSizeImage = bmp->width*(bmp->bpp==8 ? 1 : 3);

        /* Get the bitmap data */
        for (i=0;i<bmp->height;i++)
            {
            unsigned char *p;
            /* int     status; */

            p=&bmp->data[i*bytewidth];
            /* status= */ BitBlt(memDC,0,0,bmp->width,1,hDC,x0,y0+i,SRCCOPY);
            /* status= */ GetDIBits(memDC,hBitmap,0,1,p,bmi,DIB_RGB_COLORS);
            }
        if (bmp->bpp==24)
            bmp24_flip_rgb(bmp);
        }
    /* Extract the palette (seems to work) */
    if (bmp->bpp==8)
        for (i=0;i<256;i++)
            {
            bmp->red[i]   = bmi->bmiColors[i].rgbRed;
            bmp->green[i] = bmi->bmiColors[i].rgbGreen;
            bmp->blue[i]  = bmi->bmiColors[i].rgbBlue;
            }

    /* Clean up */
    DeleteDC(memDC);
    DeleteObject(hBitmap);
    ReleaseDC(h,hDC);
    return(0);
    }
Ejemplo n.º 5
0
/*
** Display bitmap <bmp> into HDC.
**
** x0,y0 = top left corner of destination rectangle in HDC
** width,height = width and height of destination rectangle in HDC
** xs,ys = top left corner of where the source pixels come from in the
**         bitmap.  E.g. xs,ys = 0,0 means the top left corner of the
**         source bitmap is placed at x0,y0 in the destination device.
*/
void bmp_blit_to_hdc_ex(WILLUSBITMAP *bmp,void *hdc,int x0,int y0,int width,int height,
                        int xs,int ys)

    {
    HDC hDC;
    BITMAPINFO *bmi;
    int i,bytewidth,w,bpp;
    /* Worst case size (8-bit w/palette) */
    static char _bmih[sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)];

    hDC=(HDC)hdc;
    /*
    ** Allocate bit map info structure (has to be allocated due to
    ** arbitrarily sized color palette ==> cannot be statically declared)
    */
    bmi = (BITMAPINFO *)_bmih;
    bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi->bmiHeader.biWidth = bmp->width;
    bmi->bmiHeader.biHeight = bmp->height;
    bmi->bmiHeader.biPlanes = 1;
    bmi->bmiHeader.biBitCount = bmp->bpp;
    bmi->bmiHeader.biCompression = BI_RGB;
    bmi->bmiHeader.biSizeImage = bmp->width*bmp->height*(bmp->bpp==8 ? 1 : 3);
    bmi->bmiHeader.biXPelsPerMeter = 72;
    bmi->bmiHeader.biYPelsPerMeter = 72;
    bmi->bmiHeader.biClrUsed = 0;
    bmi->bmiHeader.biClrImportant = 0;
    /*
    ** Set up GIF palette
    */
    if (bmp->bpp==8)
        {
        for (i=0;i<256;i++)
            {
            bmi->bmiColors[i].rgbRed   = bmp->red[i];
            bmi->bmiColors[i].rgbGreen = bmp->green[i];
            bmi->bmiColors[i].rgbBlue  = bmp->blue[i];
            bmi->bmiColors[i].rgbReserved = 0;
            }
        bmp8_win32_palette_set(bmp);
        if (bmp8_palette!=NULL)
            {
            SelectPalette(hDC,bmp8_palette,FALSE);
            RealizePalette(hDC);
            }
        }

    if (bmp->type==WILLUSBITMAP_TYPE_WIN32)
        {
        if (xs==0 && ys==0 && width==bmp->width && height==bmp->height)
            {
            SetDIBitsToDevice(hDC,x0,y0,bmp->width,bmp->height,0,0,0,bmp->height,
                              bmp->data,bmi,DIB_RGB_COLORS);
            return;
            }
        }
    if (bmp->type!=WILLUSBITMAP_TYPE_WIN32 && bmp->bpp==24)
        bmp24_flip_rgb(bmp);
    bpp = bmp->bpp==24 ? 3 : 1;
    w = width < bmp->width-xs ? width : bmp->width-xs;
    bytewidth = bmp_bytewidth(bmp);
    for (i=ys;i<bmp->height && i<ys+height;i++)
        SetDIBitsToDevice(hDC,x0,i+y0-ys,w,1,0,0,0,1,
                      &bmp->data[i*bytewidth]+bpp*xs,bmi,DIB_RGB_COLORS);
    if (bmp->type!=WILLUSBITMAP_TYPE_WIN32 && bmp->bpp==24)
        bmp24_flip_rgb(bmp);
    /*
    else
        {
        w = width < bmp->width-xs ? width : bmp->width-xs;
        bytewidth = bmp_bytewidth(bmp);
        for (i=ys;i<bmp->height && i<ys+height;i++)
            SetDIBitsToDevice(hDC,x0,i+y0,w,1,0,0,0,1,
                          &bmp->data[i*bytewidth],bmi,DIB_RGB_COLORS);
        if (bmp->bpp==24)
            bmp24_flip_rgb(bmp);
        }
    */
    }
Ejemplo n.º 6
0
void k2pdfopt_reflow_bmp(KOPTContext *kctx) {
    K2PDFOPT_SETTINGS _k2settings, *k2settings;
    MASTERINFO _masterinfo, *masterinfo;
    WILLUSBITMAP _srcgrey, *srcgrey;
    WILLUSBITMAP *src, *dst;
    BMPREGION region;
    int i, bw, marbot, marleft;

    src = &kctx->src;
    srcgrey = &_srcgrey;
    bmp_init(srcgrey);

    k2settings = &_k2settings;
    masterinfo = &_masterinfo;
    /* Initialize settings */
    k2pdfopt_settings_init_from_koptcontext(k2settings, kctx);
    k2pdfopt_settings_quick_sanity_check(k2settings);
    /* Init for new source doc */
    k2pdfopt_settings_new_source_document_init(k2settings);
    /* Init master output structure */
    masterinfo_init(masterinfo, k2settings);
    wrapbmp_init(&masterinfo->wrapbmp, k2settings->dst_color);
    /* Init new source bitmap */
    bmpregion_init(&region);
    masterinfo_new_source_page_init(masterinfo, k2settings, src, srcgrey, NULL,
            &region, k2settings->src_rot, NULL, NULL, 1, -1, NULL );
    /* Set output size */
    k2pdfopt_settings_set_margins_and_devsize(k2settings,&region,masterinfo,-1.,0);
    /* Process single source page */
    bmpregion_source_page_add(&region, k2settings, masterinfo, 1, 0);
    wrapbmp_flush(masterinfo, k2settings, 0);

    if (fabs(k2settings->dst_gamma - 1.0) > .001)
        bmp_gamma_correct(&masterinfo->bmp, &masterinfo->bmp,
                k2settings->dst_gamma);

    /* copy master bitmap to context dst bitmap */
    dst = &kctx->dst;
    marbot = (int) (k2settings->dst_dpi * k2settings->dstmargins.box[1] + .5);
    marleft = (int) (k2settings->dst_dpi * k2settings->dstmargins.box[0] + .5);
    dst->bpp = masterinfo->bmp.bpp;
    dst->width = masterinfo->bmp.width;
    dst->height = masterinfo->rows > kctx->page_height ? masterinfo->rows + marbot : kctx->page_height;
    bmp_alloc(dst);
    bmp_fill(dst, 255, 255, 255);
    bw = bmp_bytewidth(&masterinfo->bmp);
    for (i = 0; i < masterinfo->rows; i++)
        memcpy(bmp_rowptr_from_top(dst, i),
                bmp_rowptr_from_top(&masterinfo->bmp, i), bw);

    kctx->page_width = kctx->dst.width;
    kctx->page_height = kctx->dst.height;
    kctx->precache = 0;

    int j;
    BOXA *rboxa = boxaCreate(masterinfo->rectmaps.n);
    BOXA *nboxa = boxaCreate(masterinfo->rectmaps.n);
    for (j = 0; j < masterinfo->rectmaps.n; j++) {
        WRECTMAP * rectmap = &masterinfo->rectmaps.wrectmap[j];
        rectmap->coords[1].x += marleft;
        BOX* rlbox = boxCreate(rectmap->coords[1].x,
                              rectmap->coords[1].y,
                              rectmap->coords[2].x,
                              rectmap->coords[2].y);
        BOX* nlbox = boxCreate(rectmap->coords[0].x*k2settings->src_dpi/rectmap->srcdpiw/kctx->zoom + kctx->bbox.x0,
                              rectmap->coords[0].y*k2settings->src_dpi/rectmap->srcdpih/kctx->zoom + kctx->bbox.y0,
                              rectmap->coords[2].x*k2settings->src_dpi/rectmap->srcdpiw/kctx->zoom,
                              rectmap->coords[2].y*k2settings->src_dpi/rectmap->srcdpih/kctx->zoom);
        boxaAddBox(rboxa, rlbox, L_INSERT);
        boxaAddBox(nboxa, nlbox, L_INSERT);
        wrectmaps_add_wrectmap(&kctx->rectmaps, rectmap);

        /*printf("rectmap:coords:\t%.1f %.1f\t%.1f %.1f\t%.1f %.1f\t%.1f %.1f\n",
                rectmap->coords[0].x, rectmap->coords[0].y,
                rectmap->coords[1].x, rectmap->coords[1].y,
                rectmap->coords[2].x, rectmap->coords[2].y,
                rectmap->srcdpiw,     rectmap->srcdpih);*/
    }
    /* 2D sort the bounding boxes of these words. */
    BOXAA *rbaa = boxaSort2d(rboxa, NULL, 3, -5, 5);
    BOXAA *nbaa = boxaSort2d(nboxa, NULL, 3, -5, 5);

    /* Flatten the boxaa, saving the boxa index for each box */
    kctx->rboxa = boxaaFlattenToBoxa(rbaa, &kctx->rnai, L_CLONE);
    kctx->nboxa = boxaaFlattenToBoxa(nbaa, &kctx->nnai, L_CLONE);

    boxaDestroy(&rboxa);
    boxaaDestroy(&rbaa);
    boxaDestroy(&nboxa);
    boxaaDestroy(&nbaa);

    bmp_free(src);
    bmp_free(srcgrey);
    bmpregion_free(&region);
    masterinfo_free(masterinfo, k2settings);
}
Ejemplo n.º 7
0
// static int bcount=0;
void wrapbmp_add(WRAPBMP *wrapbmp,BMPREGION *region,K2PDFOPT_SETTINGS *k2settings,
                 MASTERINFO *masterinfo,int colgap,int just_flags)

    {
    WILLUSBITMAP *tmp,_tmp;
    int i,rh,th,bw,new_base,h2,bpp,width0;
// static char filename[256];

#if (WILLUSDEBUGX & 205)
k2printf("@wrapbmp->add %d x %d (w=%d).\n",region->c2-region->c1+1,region->r2-region->r1+1,wrapbmp->bmp.width);
printf("    line_spacing=%d\n",region->bbox.rowheight);
#endif
    /* Figure out if what we're adding ends in a hyphen */
    bmpregion_hyphen_detect(region,k2settings->hyphen_detect,k2settings->src_left_to_right);
    if (wrapbmp_ends_in_hyphen(wrapbmp))
        colgap=0;
    wrapbmp_hyphen_erase(wrapbmp,k2settings);
    wrapbmp->just_flushed_internal=0;  // Reset "just flushed" flag
    if (wrapbmp->bmp.width==0)
        wrapbmp->textrow=region->bbox;
    else
        {
        if (region->bbox.rowheight > wrapbmp->textrow.rowheight)
            wrapbmp->textrow.rowheight = region->bbox.rowheight;
        if (region->bbox.gap > wrapbmp->textrow.gap)
            wrapbmp->textrow.gap = region->bbox.gap;
        if (region->bbox.gapblank > wrapbmp->textrow.gapblank)
            wrapbmp->textrow.gapblank = region->bbox.gapblank;
        }
    wrapbmp->bgcolor=region->bgcolor;
    wrapbmp->just=just_flags;
    if (wrapbmp->mandatory_region_gap<0)
        {
        wrapbmp->mandatory_region_gap=masterinfo->mandatory_region_gap;
        wrapbmp->page_region_gap_in=masterinfo->page_region_gap_in;
        masterinfo->mandatory_region_gap=0;
        masterinfo->page_region_gap_in=-1.;
#if (WILLUSDEBUGX & 0x200)
aprintf(ANSI_RED "mi->mandatory_region_gap change to %d by wrap_add." ANSI_NORMAL "\n",masterinfo->mandatory_region_gap);
#endif
        }
#if (WILLUSDEBUGX & 4)
k2printf("    c1=%d, c2=%d, r1=%d, r2=%d\n",region->c1,region->c2,region->r1,region->r2);
k2printf("    colgap=%d, line_spacing=%d, rowbase=%d, row gap=%d\n",colgap,region->bbox.rowheight,region->bbox.rowbase,region->bbox.gap);
#endif
    bpp=k2settings->dst_color?3:1;
    rh=region->bbox.rowbase-region->r1+1;
    if (rh > wrapbmp->rhmax)
        wrapbmp->rhmax=rh;
    th = rh + (region->r2-region->bbox.rowbase);
    if (th > wrapbmp->thmax)
        wrapbmp->thmax=th;
#if (WILLUSDEBUGX & 4)
{
static int bcount=0;
char filename[256];
sprintf(filename,"out%05d.png",bcount++);
bmpregion_write(region,filename);
}
#endif
    if (wrapbmp->bmp.width==0)
        {
        /* Put appropriate gap in */
/*
        if (k2settings->last_rowbase_internal>=0 && rh < wrapbmp->textrow.rowheight-k2settings->last_rowbase_internal)
            {
            rh = wrapbmp->textrow.rowheight - k2settings->last_rowbase_internal;
            if (rh<2)
                rh=2;
            th = rh + (region->r2-region->bbox.rowbase);
            wrapbmp->height_extended=0;
            }
        else
            wrapbmp->height_extended=(k2settings->last_rowbase_internal>=0);
*/
        wrapbmp->base = rh-1;
        wrapbmp->bmp.height = th;
#if (WILLUSDEBUGX & 4)
k2printf("    bmpheight set to %d (line spacing=%d)\n",wrapbmp->bmp.height,wrapbmp->textrow.rowheight);
#endif
        wrapbmp->bmp.width=region->c2-region->c1+1;
        bmp_alloc(&wrapbmp->bmp);
        bw=bmp_bytewidth(&wrapbmp->bmp);
        memset(bmp_rowptr_from_top(&wrapbmp->bmp,0),255,bw*wrapbmp->bmp.height);
        for (i=region->r1;i<=region->r2;i++)
            {
            unsigned char *d,*s;
            d=bmp_rowptr_from_top(&wrapbmp->bmp,wrapbmp->base+(i-region->bbox.rowbase));
            s=bmp_rowptr_from_top(k2settings->dst_color?region->bmp:region->bmp8,i)+bpp*region->c1;
            memcpy(d,s,bw);
            }
#ifdef WILLUSDEBUG
if (wrapbmp->bmp.height<=wrapbmp->base)
{
k2printf("1. SCREEECH!\n");
k2printf("wrapbmp = %d x %d, base=%d\n",wrapbmp->bmp.width,wrapbmp->bmp.height,wrapbmp->base);
exit(10);
}
#endif
        /* Copy hyphen info from added region */
        wrapbmp->hyphen = region->bbox.hyphen;
        if (wrapbmp_ends_in_hyphen(wrapbmp))
            {
            wrapbmp->hyphen.r1 += (wrapbmp->base-region->bbox.rowbase);
            wrapbmp->hyphen.r2 += (wrapbmp->base-region->bbox.rowbase);
            wrapbmp->hyphen.ch -= region->c1;
            wrapbmp->hyphen.c2 -= region->c1;
            }
        /* Map to source page */
        {
        WRECTMAP _wrmap,*wrmap;

        wrmap=&_wrmap;
        wrmap->srcpageno = region->pageno;
        wrmap->srcwidth = region->bmp8->width;
        wrmap->srcheight = region->bmp8->height;
        wrmap->srcdpiw = wrmap->srcdpih = region->dpi;
        wrmap->srcrot = region->rotdeg;
        wrmap->coords[0].x = region->c1;
        wrmap->coords[0].y = region->r1;
        wrmap->coords[1].x = 0;
        wrmap->coords[1].y = wrapbmp->base+(region->r1-region->bbox.rowbase);
        wrmap->coords[2].x = region->c2-region->c1+1;
        wrmap->coords[2].y = region->r2-region->r1+1;
#if (WILLUSDEBUGX & 0x400)
    printf("@wrapbmp:  (x0,y0) = (%5.1f,%5.1f)\n",region->c1*72./region->dpi,region->r1*72./region->dpi);
printf("      %5.1f x %5.1f\n",(region->c2-region->c1+1)*72./region->dpi,(region->r2-region->r1+1)*72./region->dpi);
printf("      New bitmap = %d x %d\n",wrapbmp->bmp.width,wrapbmp->bmp.height);
#endif
        wrectmaps_add_wrectmap(&wrapbmp->wrectmaps,wrmap);
        }
        return;
        }
    width0=wrapbmp->bmp.width; /* Starting wrapbmp width */
    tmp=&_tmp;
    bmp_init(tmp);
    bmp_copy(tmp,&wrapbmp->bmp);
    tmp->width += colgap+region->c2-region->c1+1;
    if (rh > wrapbmp->base)
        {
        /* wrapbmp->height_extended=1; */
        new_base = rh-1;
        }
    else
        new_base = wrapbmp->base;
    if (region->r2-region->bbox.rowbase > wrapbmp->bmp.height-1-wrapbmp->base)
        h2=region->r2-region->bbox.rowbase;
    else
        h2=wrapbmp->bmp.height-1-wrapbmp->base;
    tmp->height = new_base + h2 + 1;
    bmp_alloc(tmp);
    bw=bmp_bytewidth(tmp);
    memset(bmp_rowptr_from_top(tmp,0),255,bw*tmp->height);
    bw=bmp_bytewidth(&wrapbmp->bmp);
#if (WILLUSDEBUGX & 4)
k2printf("3.  wbh=%d x %d, tmp=%d x %d x %d, new_base=%d, wbbase=%d\n",wrapbmp->bmp.width,wrapbmp->bmp.height,tmp->width,tmp->height,tmp->bpp,new_base,wrapbmp->base);
#endif

    /* Adjust previous mappings to source pages since WRAPBMP rectangle has been re-sized */
    if (new_base!=wrapbmp->base)
        for (i=0;i<wrapbmp->wrectmaps.n;i++)
            {
            wrapbmp->wrectmaps.wrectmap[i].coords[1].y += (new_base-wrapbmp->base);
            if (k2settings->src_left_to_right==0)
                wrapbmp->wrectmaps.wrectmap[i].coords[1].x += tmp->width-1-wrapbmp->bmp.width;
            }
    for (i=0;i<wrapbmp->bmp.height;i++)
        {
        unsigned char *d,*s;
        d=bmp_rowptr_from_top(tmp,i+new_base-wrapbmp->base)
                 + (k2settings->src_left_to_right ? 0 : tmp->width-1-wrapbmp->bmp.width)*bpp;
        s=bmp_rowptr_from_top(&wrapbmp->bmp,i);
        memcpy(d,s,bw);
        }
    bw=bpp*(region->c2-region->c1+1);
    if (region->r1+new_base-region->bbox.rowbase<0 || region->r2+new_base-region->bbox.rowbase>tmp->height-1)
        {
        k2printf(ANSI_YELLOW "INTERNAL ERROR--TMP NOT DIMENSIONED PROPERLY.\n");
        k2printf("(%d-%d), tmp->height=%d\n" ANSI_NORMAL,
            region->r1+new_base-region->bbox.rowbase,
            region->r2+new_base-region->bbox.rowbase,tmp->height);
        exit(10);
        }
    for (i=region->r1;i<=region->r2;i++)
        {
        unsigned char *d,*s;

        d=bmp_rowptr_from_top(tmp,i+new_base-region->bbox.rowbase)
                 + (k2settings->src_left_to_right ? wrapbmp->bmp.width+colgap : 0)*bpp;
        s=bmp_rowptr_from_top(k2settings->dst_color?region->bmp:region->bmp8,i)+bpp*region->c1;
        memcpy(d,s,bw);
        }
    {
    WRECTMAP _wrmap,*wrmap;

    wrmap=&_wrmap;
    wrmap->srcpageno = region->pageno;
    wrmap->srcwidth = region->bmp8->width;
    wrmap->srcheight = region->bmp8->height;
    wrmap->srcdpiw = wrmap->srcdpih = region->dpi;
    wrmap->srcrot = region->rotdeg;
    wrmap->coords[0].x = region->c1;
    wrmap->coords[0].y = region->r1;
    wrmap->coords[1].x = k2settings->src_left_to_right ? wrapbmp->bmp.width+colgap : 0;
    wrmap->coords[1].y = region->r1+new_base-region->bbox.rowbase;
    wrmap->coords[2].x = region->c2-region->c1+1;
    wrmap->coords[2].y = region->r2-region->r1+1;
#if (WILLUSDEBUGX & 0x400)
printf("@wrapbmp:  (x0,y0) = (%5.1f,%5.1f)\n",region->c1*72./region->dpi,region->r1*72./region->dpi);
printf("      org bmp = %d x %d\n",wrapbmp->bmp.width,wrapbmp->bmp.height);
printf("      new_base=%d, r_base=%d\n",new_base,region->bbox.rowbase);
printf("      (x1,y1) = (%g,%g)\n",wrmap->coords[1].x,wrmap->coords[1].y);
printf("      %5.1f x %5.1f\n",(region->c2-region->c1+1)*72./region->dpi,(region->r2-region->r1+1)*72./region->dpi);
printf("      New bitmap = %d x %d\n",tmp->width,tmp->height);
#endif
    wrectmaps_add_wrectmap(&wrapbmp->wrectmaps,wrmap);
    }
    bmp_copy(&wrapbmp->bmp,tmp);
#if (WILLUSDEBUGX & 4)
{
static int rcount=0;
char filename[256];
sprintf(filename,"result%03d.png",rcount++);
bmp_write(tmp,filename,stdout,100);
}
#endif
    bmp_free(tmp);
    /* Copy region's hyphen info */
    wrapbmp->hyphen = region->bbox.hyphen;
    if (wrapbmp_ends_in_hyphen(wrapbmp))
        {
        wrapbmp->hyphen.r1 += (new_base-region->bbox.rowbase);
        wrapbmp->hyphen.r2 += (new_base-region->bbox.rowbase);
        if (k2settings->src_left_to_right)
            {
            wrapbmp->hyphen.ch += width0+colgap-region->c1;
            wrapbmp->hyphen.c2 += width0+colgap-region->c1;
            }
        else
            {
            wrapbmp->hyphen.ch -= region->c1;
            wrapbmp->hyphen.c2 -= region->c1;
            }
        }
    wrapbmp->base=new_base;
    /* Doesn't seem to work?  v2.00 */
    /*
    wrapbmp->textrow.gap = (wrapbmp->bmp.height-1)-new_base;
    wrapbmp->textrow.gapblank = 0;
    */
#ifdef WILLUSDEBUG
if (wrapbmp->bmp.height<=wrapbmp->base)
{
k2printf("2. SCREEECH!\n");
k2printf("wrapbmp = %d x %d, base=%d\n",wrapbmp->bmp.width,wrapbmp->bmp.height,wrapbmp->base);
exit(10);
}
#endif
    }
Ejemplo n.º 8
0
// static int bcount=0;
void wrapbmp_add(WRAPBMP *wrapbmp,BMPREGION *region,K2PDFOPT_SETTINGS *k2settings,
                 int gap,int line_spacing,int rbase,int gio,int just_flags)

    {
    WILLUSBITMAP *tmp,_tmp;
    int i,rh,th,bw,new_base,h2,bpp,width0;
// static char filename[256];

#ifdef WILLUSDEBUG
printf("@wrapbmp->add %d x %d (w=%d).\n",region->c2-region->c1+1,region->r2-region->r1+1,wrapbmp->bmp.width);
#endif
    /* Figure out if what we're adding ends in a hyphen */
    bmpregion_hyphen_detect(region,k2settings->hyphen_detect,k2settings->src_left_to_right);
    if (wrapbmp_ends_in_hyphen(wrapbmp))
        gap=0;
    wrapbmp_hyphen_erase(wrapbmp,k2settings);
    wrapbmp->just_flushed_internal=0;  // Reset "just flushed" flag
    wrapbmp->beginning_gap_internal = -1; // Reset top-of-page or top-of-column gap
    wrapbmp->last_h5050_internal = -1; // Reset last row font size
    if (line_spacing > wrapbmp->line_spacing)
        wrapbmp->line_spacing = line_spacing;
    if (gio > wrapbmp->gap)
        wrapbmp->gap = gio;
    wrapbmp->bgcolor=region->bgcolor;
    wrapbmp->just=just_flags;
/*
printf("    c1=%d, c2=%d, r1=%d, r2=%d\n",region->c1,region->c2,region->r1,region->r2);
printf("    gap=%d, line_spacing=%d, rbase=%d, gio=%d\n",gap,line_spacing,rbase,gio);
*/
    bpp=k2settings->dst_color?3:1;
    rh=rbase-region->r1+1;
    if (rh > wrapbmp->rhmax)
        wrapbmp->rhmax=rh;
    th = rh + (region->r2-rbase);
    if (th > wrapbmp->thmax)
        wrapbmp->thmax=th;
/*
{
WILLUSBITMAP *bmp,_bmp;

bmp=&_bmp;
bmp_init(bmp);
bmp->height=region->r2-region->r1+1;
bmp->width=region->c2-region->c1+1;
bmp->bpp=bpp*8;
if (bpp==1)
for (i=0;i<256;i++)
bmp->red[i]=bmp->blue[i]=bmp->green[i]=i;
bmp_alloc(&wrapbmp->bmp);
bw=bmp_bytewidth(&wrapbmp->bmp);
memset(bmp_rowptr_from_top(bmp,0),255,bw*bmp->height);
for (i=region->r1;i<=region->r2;i++)
{
unsigned char *d,*s;
d=bmp_rowptr_from_top(bmp,i-region->r1);
s=bmp_rowptr_from_top(k2settings->dst_color?region->bmp:region->bmp8,i)+bpp*region->c1;
if (i==rbase)
memset(d,0,bw);
else
memcpy(d,s,bw);
}
sprintf(filename,"out%05d.png",bcount++);
bmp_write(bmp,filename,stdout,100);
bmp_free(bmp);
}
*/
    if (wrapbmp->bmp.width==0)
        {
        /* Put appropriate gap in */
        if (k2settings->last_rowbase_internal>=0 && rh < wrapbmp->line_spacing-k2settings->last_rowbase_internal)
            {
            rh = wrapbmp->line_spacing - k2settings->last_rowbase_internal;
            if (rh<2)
                rh=2;
            th = rh + (region->r2-rbase);
            wrapbmp->height_extended=0;
            }
        else
            wrapbmp->height_extended=(k2settings->last_rowbase_internal>=0);
        wrapbmp->base = rh-1;
        wrapbmp->bmp.height = th;
#ifdef WILLUSDEBUG
printf("@wrapbmp->add:  bmpheight set to %d (wls=%d, lrbi=%d)\n",wrapbmp->bmp.height,wrapbmp->line_spacing,k2settings->last_rowbase_internal);
#endif
        wrapbmp->bmp.width=region->c2-region->c1+1;
        bmp_alloc(&wrapbmp->bmp);
        bw=bmp_bytewidth(&wrapbmp->bmp);
        memset(bmp_rowptr_from_top(&wrapbmp->bmp,0),255,bw*wrapbmp->bmp.height);
        for (i=region->r1;i<=region->r2;i++)
            {
            unsigned char *d,*s;
            d=bmp_rowptr_from_top(&wrapbmp->bmp,wrapbmp->base+(i-rbase));
            s=bmp_rowptr_from_top(k2settings->dst_color?region->bmp:region->bmp8,i)+bpp*region->c1;
            memcpy(d,s,bw);
            }
#ifdef WILLUSDEBUG
if (wrapbmp->bmp.height<=wrapbmp->base)
{
printf("1. SCREEECH!\n");
printf("wrapbmp = %d x %d, base=%d\n",wrapbmp->bmp.width,wrapbmp->bmp.height,wrapbmp->base);
exit(10);
}
#endif
        /* Copy hyphen info from added region */
        wrapbmp->hyphen = region->hyphen;
        if (wrapbmp_ends_in_hyphen(wrapbmp))
            {
            wrapbmp->hyphen.r1 += (wrapbmp->base-rbase);
            wrapbmp->hyphen.r2 += (wrapbmp->base-rbase);
            wrapbmp->hyphen.ch -= region->c1;
            wrapbmp->hyphen.c2 -= region->c1;
            }
        return;
        }
    width0=wrapbmp->bmp.width; /* Starting wrapbmp width */
    tmp=&_tmp;
    bmp_init(tmp);
    bmp_copy(tmp,&wrapbmp->bmp);
    tmp->width += gap+region->c2-region->c1+1;
    if (rh > wrapbmp->base)
        {
        wrapbmp->height_extended=1;
        new_base = rh-1;
        }
    else
        new_base = wrapbmp->base;
    if (region->r2-rbase > wrapbmp->bmp.height-1-wrapbmp->base)
        h2=region->r2-rbase;
    else
        h2=wrapbmp->bmp.height-1-wrapbmp->base;
    tmp->height = new_base + h2 + 1;
    bmp_alloc(tmp);
    bw=bmp_bytewidth(tmp);
    memset(bmp_rowptr_from_top(tmp,0),255,bw*tmp->height);
    bw=bmp_bytewidth(&wrapbmp->bmp);
/*
printf("3.  wbh=%d x %d, tmp=%d x %d x %d, new_base=%d, wbbase=%d\n",wrapbmp->bmp.width,wrapbmp->bmp.height,tmp->width,tmp->height,tmp->bpp,new_base,wrapbmp->base);
*/
    for (i=0;i<wrapbmp->bmp.height;i++)
        {
        unsigned char *d,*s;
        d=bmp_rowptr_from_top(tmp,i+new_base-wrapbmp->base)
                 + (k2settings->src_left_to_right ? 0 : tmp->width-1-wrapbmp->bmp.width)*bpp;
        s=bmp_rowptr_from_top(&wrapbmp->bmp,i);
        memcpy(d,s,bw);
        }
    bw=bpp*(region->c2-region->c1+1);
    if (region->r1+new_base-rbase<0 || region->r2+new_base-rbase>tmp->height-1)
        {
        aprintf(ANSI_YELLOW "INTERNAL ERROR--TMP NOT DIMENSIONED PROPERLY.\n");
        aprintf("(%d-%d), tmp->height=%d\n" ANSI_NORMAL,
            region->r1+new_base-rbase,
            region->r2+new_base-rbase,tmp->height);
        exit(10);
        }
    for (i=region->r1;i<=region->r2;i++)
        {
        unsigned char *d,*s;

        d=bmp_rowptr_from_top(tmp,i+new_base-rbase)
                 + (k2settings->src_left_to_right ? wrapbmp->bmp.width+gap : 0)*bpp;
        s=bmp_rowptr_from_top(k2settings->dst_color?region->bmp:region->bmp8,i)+bpp*region->c1;
        memcpy(d,s,bw);
        }
    bmp_copy(&wrapbmp->bmp,tmp);
    bmp_free(tmp);
    /* Copy region's hyphen info */
    wrapbmp->hyphen = region->hyphen;
    if (wrapbmp_ends_in_hyphen(wrapbmp))
        {
        wrapbmp->hyphen.r1 += (new_base-rbase);
        wrapbmp->hyphen.r2 += (new_base-rbase);
        if (k2settings->src_left_to_right)
            {
            wrapbmp->hyphen.ch += width0+gap-region->c1;
            wrapbmp->hyphen.c2 += width0+gap-region->c1;
            }
        else
            {
            wrapbmp->hyphen.ch -= region->c1;
            wrapbmp->hyphen.c2 -= region->c1;
            }
        }
    wrapbmp->base=new_base;
#ifdef WILLUSDEBUG
if (wrapbmp->bmp.height<=wrapbmp->base)
{
printf("2. SCREEECH!\n");
printf("wrapbmp = %d x %d, base=%d\n",wrapbmp->bmp.width,wrapbmp->bmp.height,wrapbmp->base);
exit(10);
}
#endif
    }
Ejemplo n.º 9
0
/*
** bmp must be grayscale! (cbmp might be color, might be grayscale, can be null)
** Handles cbmp either 8-bit or 24-bit in v2.10.
*/
void bmp_detect_vertical_lines(WILLUSBITMAP *bmp,WILLUSBITMAP *cbmp,
                               double dpi,/* double minwidth_in, */
                               double maxwidth_in,double minheight_in,double anglemax_deg,
                               int white_thresh,int erase_vertical_lines,int debug,int verbose)

    {
    int tc,iangle,irow,icol;
    int rowstep,na,angle_sign,ccthresh;
    int halfwidth,bytewidth;
    int bs1,nrsteps;
    double anglestep;
    WILLUSBITMAP *tmp,_tmp;
    unsigned char *p0;
    unsigned char *t0;

    if (debug)
        k2printf("At bmp_detect_vertical_lines...\n");
    if (!bmp_is_grayscale(bmp))
        {
        k2printf("Internal error.  bmp_detect_vertical_lines passed a non-grayscale bitmap.\n");
        exit(10);
        }
    tmp=&_tmp;
    bmp_init(tmp);
    bmp_copy(tmp,bmp);
    p0=bmp_rowptr_from_top(bmp,0);
    t0=bmp_rowptr_from_top(tmp,0);
    bytewidth=bmp_bytewidth(bmp);
    /*
    pixmin = (int)(minwidth_in*dpi+.5);
    if (pixmin<1)
        pixmin=1;
    halfwidth=pixmin/4;
    if (halfwidth<1)
        halfwidth=1; 
    */
    halfwidth=1;
    anglestep=atan2((double)halfwidth/dpi,minheight_in);
    na=(int)((anglemax_deg*PI/180.)/anglestep+.5);
    if (na<1)
        na=1;
    rowstep=(int)(dpi/40.+.5);
    if (rowstep<2)
        rowstep=2;
    nrsteps=bmp->height/rowstep;
    bs1=bytewidth*rowstep;
    ccthresh=(int)(minheight_in*dpi/rowstep+.5);
    if (ccthresh<2)
        ccthresh=2;
    if (debug && verbose)
        k2printf("    na = %d, rowstep = %d, ccthresh = %d, white_thresh = %d, nrsteps=%d\n",na,rowstep,ccthresh,white_thresh,nrsteps);
/*
bmp_write(bmp,"out.png",stdout,97);
wfile_written_info("out.png",stdout);
*/
    for (tc=0;tc<100;tc++)
        {
        int ccmax,ic0max,ir0max;
        double tanthmax;

        ccmax=-1;
        ic0max=ir0max=0;
        tanthmax=0.;
        for (iangle=0;iangle<=na;iangle++)
            {
            for (angle_sign=1;angle_sign>=-1;angle_sign-=2)
                {
                double th,tanth,tanthx;
                int ic1,ic2;

                if (iangle==0 && angle_sign==-1)
                    continue;
                th=(PI/180.)*iangle*angle_sign*fabs(anglemax_deg)/na;
                tanth=tan(th);
                tanthx=tanth*rowstep;
                if (angle_sign==1)
                    {
                    ic1=-(int)(bmp->height*tanth+1.);
                    ic2=bmp->width-1;
                    }
                else
                    {
                    ic1=(int)(-bmp->height*tanth+1.);
                    ic2=bmp->width-1+(int)(-bmp->height*tanth+1.);
                    }
// k2printf("iangle=%2d, angle_sign=%2d, ic1=%4d, ic2=%4d\n",iangle,angle_sign,ic1,ic2);
                for (icol=ic1;icol<=ic2;icol++)
                    {
                    unsigned char *p,*t;
                    int cc,ic0,ir0;
                    p=p0;
                    t=t0;
                    if (icol<0 || icol>bmp->width-1)
                        for (irow=0;irow<nrsteps;irow++,p+=bs1,t+=bs1)
                            {
                            int ic;
                            ic=icol+irow*tanthx;
                            if (ic>=0 && ic<bmp->width)
                                break;
                            }
                    else
                        irow=0;
                    for (ir0=ic0=cc=0;irow<nrsteps;irow++,p+=bs1,t+=bs1)
                        {
                        int ic;
                        ic=icol+irow*tanthx;
                        if (ic<0 || ic>=bmp->width)
                            break;
                        if ((p[ic]<white_thresh || p[ic+bytewidth]<white_thresh)
                            && (t[ic]<white_thresh || t[ic+bytewidth]<white_thresh))
                            {
                            if (cc==0)
                                {
                                ic0=ic;
                                ir0=irow*rowstep;
                                }
                            cc++;
                            if (cc>ccmax)
                                {
                                ccmax=cc;
                                tanthmax=tanth;
                                ic0max=ic0;
                                ir0max=ir0;
                                }
                            }
                        else
                            cc=0;
                        }
                    }
                }
            }
        if (ccmax<ccthresh)
            break;
        if (debug)
            k2printf("    Vert line detected:  ccmax=%d (pix=%d), tanthmax=%g, ic0max=%d, ir0max=%d\n",ccmax,ccmax*rowstep,tanthmax,ic0max,ir0max);
        if (!vert_line_erase(bmp,cbmp,tmp,ir0max,ic0max,tanthmax,minheight_in,
                             /*minwidth_in,*/ maxwidth_in,white_thresh,dpi,erase_vertical_lines))
            break;
        }
/*
bmp_write(tmp,"outt.png",stdout,95);
wfile_written_info("outt.png",stdout);
bmp_write(bmp,"out2.png",stdout,95);
wfile_written_info("out2.png",stdout);
exit(10);
*/
    /* v2.20--fix memory leak here */
    bmp_free(tmp);
    }
Ejemplo n.º 10
0
/*
** Returns 0 for success, negative number for error code.
** bpp can be 24 or 8.
**
*/
int bmpdjvu_djvufile_to_bmp(WILLUSBITMAP *bmp,char *infile,int pageno,
                            int dpi,int bpp,FILE *out)

    {
    ddjvu_context_t *ctx;
    ddjvu_document_t *doc;
    ddjvu_page_t *page;
    /* ddjvu_page_type_t type; */
    ddjvu_rect_t prect;
    ddjvu_rect_t rrect;
    ddjvu_format_style_t style;
    ddjvu_render_mode_t mode;
    ddjvu_format_t *fmt;
    int i,iw,ih,idpi,status;

    ctx=ddjvu_context_create("bmpdjvu_djvufile_to_bmp");
    if (ctx==NULL)
        {
        nprintf(out,"Cannot create djvu context.\n");
        return(-1);
        }
    doc=ddjvu_document_create_by_filename(ctx,infile,1);
    if (doc==NULL)
        {
        ddjvu_context_release(ctx);
        nprintf(out,"Cannot create djvu document context from djvu file %s.\n",
                infile);
        return(-2);
        }
    i=ddjvu_document_get_pagenum(doc);
    if (pageno<0 || pageno>i)
        {
        ddjvu_document_release(doc);
        ddjvu_context_release(ctx);
        nprintf(out,"Page number %d is out of range for djvu file %s.\n",pageno,infile);
        return(-3);
        }
    page=ddjvu_page_create_by_pageno(doc,pageno-1);
    if (page==NULL)
        {
        ddjvu_document_release(doc);
        ddjvu_context_release(ctx);
        nprintf(out,"Cannot parse page %d of djvu file %s.\n",pageno,infile);
        return(-4);
        }
    while (!ddjvu_page_decoding_done(page))
        handle(1,ctx);
    if (ddjvu_page_decoding_error(page))
        {
        ddjvu_page_release(page);
        ddjvu_document_release(doc);
        ddjvu_context_release(ctx);
        nprintf(out,"Error decoding page %d of djvu file %s.\n",pageno,infile);
        return(-5);
        }
    /* type= */ ddjvu_page_get_type(page);
    /*
    printf("type=%d\n",type);
    description=ddjvu_page_get_long_description(page);
    printf("Description='%s'\n",description);
    */
    iw = ddjvu_page_get_width(page);
    ih = ddjvu_page_get_height(page);
    idpi = ddjvu_page_get_resolution(page);
    prect.x=prect.y=0;
    bmp->width=prect.w=iw*dpi/idpi;
    bmp->height=prect.h=ih*dpi/idpi;
    bmp->bpp=(bpp==8) ? 8 : 24;
    rrect=prect;
    bmp_alloc(bmp);
    if (bmp->bpp==8)
        {
        int ii;
        for (ii=0;ii<256;ii++)
            bmp->red[ii]=bmp->blue[ii]=bmp->green[ii]=ii;
        }
    mode=DDJVU_RENDER_COLOR;
    style=bpp==8 ? DDJVU_FORMAT_GREY8 : DDJVU_FORMAT_RGB24;
    fmt=ddjvu_format_create(style,0,0);
    if (fmt==NULL)
        {
        ddjvu_page_release(page);
        ddjvu_document_release(doc);
        ddjvu_context_release(ctx);
        nprintf(out,"Error setting DJVU format for djvu file %s (page %d).\n",infile,pageno);
        return(-6);
        }
    ddjvu_format_set_row_order(fmt,1);
    status=ddjvu_page_render(page,mode,&prect,&rrect,fmt,bmp_bytewidth(bmp),(char *)bmp->data);
    ddjvu_format_release(fmt);
    ddjvu_page_release(page);
    ddjvu_document_release(doc);
    ddjvu_context_release(ctx);
    if (!status)
        {
        nprintf(out,"Error rendering page %d of djvu file %s.\n",pageno,infile);
        return(-7);
        }
    return(0);
    }
Ejemplo n.º 11
0
static int reflowPage(lua_State *L) {
	DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
	KOPTContext *kctx = (KOPTContext*) lua_topointer(L, 2);
	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, status;

	px = 0;
	py = 0;
	pw = ddjvu_page_get_width(page->page_ref);
	ph = ddjvu_page_get_height(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);

	double zoom = kctx->zoom*kctx->quality;
	float scale = ((2*zoom*kctx->dev_width) / (double)pw + \
			 	   (2*zoom*kctx->dev_height) / (double)ph) / 2;
	prect.w = pw * scale;
	prect.h = ph * scale;
	rrect.x = rx * scale;
	rrect.y = ry * scale;
	rrect.w = rw * scale;
	rrect.h = rh * scale;
	printf("rendering page:%d,%d,%d,%d\n",rrect.x,rrect.y,rrect.w,rrect.h);
	kctx->zoom = scale;

	WILLUSBITMAP *src = &kctx->src;
	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);

	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;
}