void PDFDocument::Render( Document::PixelWriter* pw, int page, float zoom, int rotation) { assert((page >= 0) && (page < GetNumPages())); std::unique_lock<std::mutex> lock(_render_mutex); // 1. Init MuPDF structures. const fz_matrix& m = Transform(zoom, rotation); pdf_page* page_struct = GetPage(page); const fz_irect& bbox = GetBoundingBox(page_struct, m); fz_pixmap* pixmap = fz_new_pixmap_with_bbox( _fz_context, fz_device_rgb(_fz_context), FZ_OBJ(bbox), nullptr, 1); fz_device* dev = fz_new_draw_device(_fz_context, FZ_OBJ(fz_identity), pixmap); // 2. Render page. fz_clear_pixmap_with_value(_fz_context, pixmap, 0xff); pdf_run_page( _fz_context, _pdf_document, page_struct, dev, FZ_OBJ(m), nullptr); // 3. Write pixmap to buffer. The page is vertically divided into n equal // stripes, each copied to pw by one thread. assert(fz_pixmap_components(_fz_context, pixmap) == 4); uint8_t* buffer = reinterpret_cast<uint8_t*>(fz_pixmap_samples(_fz_context, pixmap)); const int num_cols = fz_pixmap_width(_fz_context, pixmap); const int num_rows = fz_pixmap_height(_fz_context, pixmap); ExecuteInParallel([=](int num_threads, int i) { const int num_rows_per_thread = num_rows / num_threads; const int y_begin = i * num_rows_per_thread; const int y_end = (i == num_threads - 1) ? num_rows : (i + 1) * num_rows_per_thread; uint8_t* p = buffer + y_begin * num_cols * 4; for (int y = y_begin; y < y_end; ++y) { for (int x = 0; x < num_cols; ++x) { pw->Write(x, y, p[0], p[1], p[2]); p += 4; } } }); // 4. Clean up. fz_close_device(_fz_context, dev); fz_drop_device(_fz_context, dev); fz_drop_pixmap(_fz_context, pixmap); }
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); }
void winblit() { int image_w = fz_pixmap_width(gapp.ctx, gapp.image); int image_h = fz_pixmap_height(gapp.ctx, gapp.image); int image_n = fz_pixmap_components(gapp.ctx, gapp.image); unsigned char *samples = fz_pixmap_samples(gapp.ctx, gapp.image); int x0 = gapp.panx; int y0 = gapp.pany; int x1 = gapp.panx + image_w; int y1 = gapp.pany + image_h; RECT r; if (gapp.image) { if (gapp.iscopying || justcopied) { pdfapp_invert(&gapp, &gapp.selr); justcopied = 1; } pdfapp_inverthit(&gapp); dibinf->bmiHeader.biWidth = image_w; dibinf->bmiHeader.biHeight = -image_h; dibinf->bmiHeader.biSizeImage = image_h * 4; if (image_n == 2) { int i = image_w * image_h; unsigned char *color = malloc(i*4); unsigned char *s = samples; unsigned char *d = color; for (; i > 0 ; i--) { d[2] = d[1] = d[0] = *s++; d[3] = *s++; d += 4; } SetDIBitsToDevice(hdc, gapp.panx, gapp.pany, image_w, image_h, 0, 0, 0, image_h, color, dibinf, DIB_RGB_COLORS); free(color); } if (image_n == 4) { SetDIBitsToDevice(hdc, gapp.panx, gapp.pany, image_w, image_h, 0, 0, 0, image_h, samples, dibinf, DIB_RGB_COLORS); } pdfapp_inverthit(&gapp); if (gapp.iscopying || justcopied) { pdfapp_invert(&gapp, &gapp.selr); justcopied = 1; } } /* Grey background */ r.top = 0; r.bottom = gapp.winh; r.left = 0; r.right = x0; FillRect(hdc, &r, bgbrush); r.left = x1; r.right = gapp.winw; FillRect(hdc, &r, bgbrush); r.left = 0; r.right = gapp.winw; r.top = 0; r.bottom = y0; FillRect(hdc, &r, bgbrush); r.top = y1; r.bottom = gapp.winh; FillRect(hdc, &r, bgbrush); /* Drop shadow */ r.left = x0 + 2; r.right = x1 + 2; r.top = y1; r.bottom = y1 + 2; FillRect(hdc, &r, shbrush); r.left = x1; r.right = x1 + 2; r.top = y0 + 2; r.bottom = y1; FillRect(hdc, &r, shbrush); winblitsearch(); }
static void winblit(pdfapp_t *app) { int image_w = fz_pixmap_width(gapp.ctx, gapp.image); int image_h = fz_pixmap_height(gapp.ctx, gapp.image); int image_n = fz_pixmap_components(gapp.ctx, gapp.image); unsigned char *image_samples = fz_pixmap_samples(gapp.ctx, gapp.image); int x0 = gapp.panx; int y0 = gapp.pany; int x1 = gapp.panx + image_w; int y1 = gapp.pany + image_h; XSetForeground(xdpy, xgc, xbgcolor.pixel); fillrect(0, 0, x0, gapp.winh); fillrect(x1, 0, gapp.winw - x1, gapp.winh); fillrect(0, 0, gapp.winw, y0); fillrect(0, y1, gapp.winw, gapp.winh - y1); XSetForeground(xdpy, xgc, xshcolor.pixel); fillrect(x0+2, y1, image_w, 2); fillrect(x1, y0+2, 2, image_h); if (gapp.iscopying || justcopied) { pdfapp_invert(&gapp, &gapp.selr); justcopied = 1; } pdfapp_inverthit(&gapp); if (image_n == 4) ximage_blit(xwin, xgc, x0, y0, image_samples, 0, 0, image_w, image_h, image_w * image_n); else if (image_n == 2) { int i = image_w*image_h; unsigned char *color = malloc(i*4); if (color) { unsigned char *s = image_samples; unsigned char *d = color; for (; i > 0 ; i--) { d[2] = d[1] = d[0] = *s++; d[3] = *s++; d += 4; } ximage_blit(xwin, xgc, x0, y0, color, 0, 0, image_w, image_h, image_w * 4); free(color); } } pdfapp_inverthit(&gapp); if (gapp.iscopying || justcopied) { pdfapp_invert(&gapp, &gapp.selr); justcopied = 1; } winblitsearch(app); if (showingpage) { char buf[42]; snprintf(buf, sizeof buf, "Page %d/%d", gapp.pageno, gapp.pagecount); windrawstringxor(&gapp, 10, 20, buf); } }
QImage Pdf::page(int i) { fz_page* page = fz_load_page(doc, i); if (page == 0) { printf("cannot load page %d\n", i); return QImage(); } static const float resolution = 300.0; const float zoom = resolution / 72.0; fz_rect bounds = fz_bound_page(doc, page); fz_matrix ctm = fz_scale(zoom, zoom); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, bounds)); fz_pixmap* pix = fz_new_pixmap_with_bbox(ctx, fz_device_gray, bbox); fz_clear_pixmap_with_value(ctx, pix, 255); fz_device* dev = fz_new_draw_device(ctx, pix); fz_run_page(doc, page, dev, ctm, NULL); fz_free_device(dev); dev = NULL; int w = fz_pixmap_width(ctx, pix); int h = fz_pixmap_height(ctx, pix); if (fz_pixmap_components(ctx, pix) != 2) { printf("omg: pixmap not bw? %d\n", fz_pixmap_components(ctx, pix)); return QImage(); } QImage image(w, h, QImage::Format_MonoLSB); QVector<QRgb> ct(2); ct[0] = qRgb(255, 255, 255); ct[1] = qRgb(0, 0, 0); image.setColorTable(ct); uchar* s = fz_pixmap_samples(ctx, pix); int bytes = w / 8; int bits = w % 8; for (int line = 0; line < h; ++line) { uchar* d = image.scanLine(line); for (int col = 0; col < bytes; ++col) { uchar data = 0; for (int i = 0; i < 8; ++i) { uchar v = *s; s += 2; data >>= 1; if (v < 128) { // convert grayscale to bw data |= 0x80; } } *d++ = data; } uchar data = 0; for (int col = 0; col < bits; ++col) { uchar v = *s; s += 2; data >>= 1; if (v < 128) data |= 0x80; } } fz_drop_pixmap(ctx, pix); return image; }
cairo_surface_t* pdf_page_image_get_cairo(zathura_page_t* page, void* data, zathura_image_t* image, zathura_error_t* error) { mupdf_page_t* mupdf_page = data; if (page == NULL || mupdf_page == NULL || image == NULL || image->data == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } goto error_ret; } fz_image* mupdf_image = (fz_image*) image->data; fz_pixmap* pixmap = NULL; cairo_surface_t* surface = NULL; pixmap = fz_get_pixmap_from_image(mupdf_page->ctx, mupdf_image, NULL, NULL, 0, 0); if (pixmap == NULL) { goto error_free; } surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, mupdf_image->w, mupdf_image->h); if (surface == NULL) { goto error_free; } unsigned char* surface_data = cairo_image_surface_get_data(surface); int rowstride = cairo_image_surface_get_stride(surface); unsigned char* s = fz_pixmap_samples(mupdf_page->ctx, pixmap); unsigned int n = fz_pixmap_components(mupdf_page->ctx, pixmap); const int height = fz_pixmap_height(mupdf_page->ctx, pixmap); const int width = fz_pixmap_width(mupdf_page->ctx, pixmap); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { guchar* p = surface_data + y * rowstride + x * 4; // RGB if (n == 4) { p[0] = s[2]; p[1] = s[1]; p[2] = s[0]; // Gray-scale or mask } else { p[0] = s[0]; p[1] = s[0]; p[2] = s[0]; } s += n; } } fz_drop_pixmap(mupdf_page->ctx, pixmap); return surface; error_free: if (pixmap != NULL) { fz_drop_pixmap(mupdf_page->ctx, pixmap); } if (surface != NULL) { cairo_surface_destroy(surface); } error_ret: return NULL; }