Beispiel #1
0
	QImage Document::RenderPage (int num, double xRes, double yRes)
	{
		auto page = WrapPage (pdf_load_page (MuDoc_, num), MuDoc_);
		if (!page)
			return QImage ();

#if MUPDF_VERSION < 0x0102
		const auto& rect = pdf_bound_page (MuDoc_, page.get ());
#else
		fz_rect rect;
		pdf_bound_page (MuDoc_, page.get (), &rect);
#endif

		auto px = fz_new_pixmap (MuCtx_, fz_device_bgr, xRes * (rect.x1 - rect.x0), yRes * (rect.y1 - rect.y0));
		fz_clear_pixmap (MuCtx_, px);
		auto dev = fz_new_draw_device (MuCtx_, px);
#if MUPDF_VERSION < 0x0102
		pdf_run_page (MuDoc_, page.get (), dev, fz_scale (xRes, yRes), NULL);
#else
		fz_matrix matrix;
		pdf_run_page (MuDoc_, page.get (), dev, fz_scale (&matrix, xRes, yRes), NULL);
#endif
		fz_free_device (dev);

		const int pxWidth = fz_pixmap_width (MuCtx_, px);
		const int pxHeight = fz_pixmap_height (MuCtx_, px);

		auto samples = fz_pixmap_samples (MuCtx_, px);

		QImage temp (samples, pxWidth, pxHeight, QImage::Format_ARGB32);
		QImage img (QSize (pxWidth, pxHeight), QImage::Format_ARGB32);

		for (int y = 0; y < pxHeight; ++y)
		{
			auto target = reinterpret_cast<QRgb*> (img.scanLine (y));
			const auto source = reinterpret_cast<QRgb*> (temp.scanLine (y));
			std::memcpy (target, source, sizeof (source [0]) * pxWidth);
		}
		fz_drop_pixmap (MuCtx_, px);

		temp = QImage (QSize (pxWidth, pxHeight), QImage::Format_ARGB32);

		QPainter p;
		p.begin (&temp);
		p.fillRect (QRect (QPoint (0, 0), temp.size ()), Qt::white);
		p.drawImage (0, 0, img);
		p.end ();
		return temp;
	}
Beispiel #2
0
static fz_display_list* _pdf_doc_get_list(
    struct _pdf_doc *self, int pageno)
{
    pdf_page *page;

    if (self->disps[pageno])
        return self->disps[pageno];

    page = _pdf_doc_get_page(self, pageno);
    if (NULL == self->disps[pageno]) {
        fz_error err;
        fz_device *mdev;

        self->disps[pageno] = fz_new_display_list();
        mdev = fz_new_list_device(self->disps[pageno]);
        err = pdf_run_page(self->xref, page, mdev, fz_identity);

        if (err) {
            mume_error(("pdf_run_page(%d): %d\n", pageno, err));
        }

        fz_free_device(mdev);
    }

    return self->disps[pageno];
}
Beispiel #3
0
void benchrenderpage(fz_context *ctx, pdf_document *xref, pdf_page *page, int pagenum)
{
	fz_device *dev;
	fz_pixmap *pix;
	fz_bbox bbox;
	mstimer timer;

	timerstart(&timer);

	bbox = fz_round_rect(pdf_bound_page(xref, page));
	pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, bbox);
	fz_clear_pixmap_with_value(ctx, pix, 0xFF);
	dev = fz_new_draw_device(ctx, pix);
	fz_try(ctx) {
		pdf_run_page(xref, page, dev, fz_identity, NULL);
		timerstop(&timer);
		logbench("pagerender %3d: %.2f ms\n", pagenum, timeinms(&timer));
	}
	fz_catch(ctx) {
		logbench("Error: pdf_run_page() failed\n");
	}

	fz_drop_pixmap(ctx, pix);
	fz_free_device(dev);
}
Beispiel #4
0
static void pdfapp_loadpage_pdf(pdfapp_t *app)
{
	pdf_page *page;
	fz_error error;
	fz_device *mdev;

	error = pdf_load_page(&page, app->xref, app->pageno - 1);
	if (error)
		pdfapp_error(app, error);

	app->page_bbox = page->mediabox;
	app->page_rotate = page->rotate;
	app->page_links = page->links;
	page->links = NULL;

	/* Create display list */
	app->page_list = fz_new_display_list();
	mdev = fz_new_list_device(app->page_list);
	error = pdf_run_page(app->xref, page, mdev, fz_identity);
	if (error)
	{
		error = fz_rethrow(error, "cannot draw page %d in '%s'", app->pageno, app->doctitle);
		pdfapp_error(app, error);
	}
	fz_free_device(mdev);

	pdf_free_page(page);

	pdf_age_store(app->xref->store, 3);
}
Beispiel #5
0
QImage Pdf::page(int i)
      {
      pdf_page* page = pdf_load_page(xref, 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_matrix ctm  = fz_translate(0, -page->mediabox.y1);
      ctm            = fz_concat(ctm, fz_scale(zoom, -zoom));
      ctm            = fz_concat(ctm, fz_rotate(page->rotate));
      fz_bbox bbox   = fz_round_rect(fz_transform_rect(ctm, page->mediabox));
      fz_pixmap* pix = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox);

      fz_clear_pixmap_with_color(pix, 255);

      fz_device* dev = fz_new_draw_device(ctx, cache, pix);
      pdf_run_page(xref, page, dev, ctm);
      fz_free_device(dev);

      int w = pix->w;
      int h = pix->h;

      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   = pix->samples;
      int stride = image.bytesPerLine();
      int bytes  = w >> 3;
      for (int line = 0; line < h; ++line) {
            uchar* d = image.bits() + stride * line;
            for (int col = 0; col < bytes; ++col) {
                  uchar data = 0;
                  for (int i = 0; i < 8; ++i) {
                        uchar v = *s++;
                        s++;
                        data >>= 1;
                        if (v < 128)
                              data |= 0x80;
                        }
                  *d++ = data;
                  }
            }
      fz_drop_pixmap(ctx, pix);
      pdf_free_page(ctx, page);
      return image;
      }
Beispiel #6
0
JNIEXPORT void JNICALL
Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int page)
{
	float zoom;
	fz_matrix ctm;
	fz_bbox bbox;
	fz_device *dev = NULL;
	pdf_page *currentPage = NULL;

	fz_var(dev);
	fz_var(currentPage);

	/* In the event of an error, ensure we give a non-empty page */
	pageWidth = 100;
	pageHeight = 100;

	LOGE("Goto page %d...", page);
	fz_try(ctx)
	{
		if (currentPageList != NULL)
		{
			fz_free_display_list(ctx, currentPageList);
			currentPageList = NULL;
		}
		pagenum = page;
		currentPage = pdf_load_page(xref, pagenum);
		zoom = resolution / 72;
		currentMediabox = pdf_bound_page(xref, currentPage);
		ctm = fz_scale(zoom, zoom);
		bbox = fz_round_rect(fz_transform_rect(ctm, currentMediabox));
		pageWidth = bbox.x1-bbox.x0;
		pageHeight = bbox.y1-bbox.y0;
		/* Render to list */
		currentPageList = fz_new_display_list(ctx);
		dev = fz_new_list_device(ctx, currentPageList);
		pdf_run_page(xref, currentPage, dev, fz_identity, NULL);
	}
	fz_catch(ctx)
	{
		LOGE("cannot make displaylist from page %d", pagenum);
	}
	pdf_free_page(ctx, currentPage);
	currentPage = NULL;
	fz_free_device(dev);
	dev = NULL;
}
Beispiel #7
0
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);
}
Beispiel #8
0
std::string PDFDocument::GetPageText(int page, int line_sep) {
  // 1. Init MuPDF structures.
  pdf_page* page_struct = GetPage(page);
  fz_stext_sheet* text_sheet = fz_new_stext_sheet(_fz_context);

  // 2. Render page.
#if MUPDF_VERSION >= 10010
  fz_stext_options stext_options = { 0 };
  // See #elif MUPDF_VERSION >= 10009 block below.
  fz_stext_page* text_page = fz_new_stext_page_from_page(
      _fz_context, &(page_struct->super), text_sheet, &stext_options);
#elif MUPDF_VERSION >= 10009
  // The function below is a wrapper around fz_run_page that uses a fresh
  // device. We can't use pdf_run_page to gather the text for us.
  // These notes are also left in here in case MuPDF's API changes again.
  fz_stext_page* text_page = fz_new_stext_page_from_page(
      _fz_context, &(page_struct->super), text_sheet);
#else
  fz_stext_page* text_page = fz_new_text_page(_fz_context);
  fz_device* dev = fz_new_stext_device(_fz_context, text_sheet, text_page);
  // I've no idea what fz_{begin,end}_page do, but without them pdf_run_page
  // segfaults :-/
  fz_begin_page(_fz_context, dev, &fz_infinite_rect, &fz_identity);
  pdf_run_page(
      _fz_context, _pdf_document, page_struct, dev, &fz_identity, nullptr);
  fz_end_page(_fz_context, dev);
#endif

  // 3. Build text.
  std::string r;
  for (fz_page_block* page_block = text_page->blocks;
       page_block < text_page->blocks + text_page->len;
       ++page_block) {
    assert(page_block != nullptr);
    if (page_block->type != FZ_PAGE_BLOCK_TEXT) {
      continue;
    }
    fz_stext_block* const text_block = page_block->u.text;
    assert(text_block != nullptr);
    for (fz_stext_line* text_line = text_block->lines;
         text_line < text_block->lines + text_block->len;
         ++text_line) {
      assert(text_line != nullptr);
      for (fz_stext_span* text_span = text_line->first_span;
           text_span != nullptr;
           text_span = text_span->next) {
        for (int i = 0; i < text_span->len; ++i) {
          const int c = text_span->text[i].c;
          // A single UTF-8 character cannot take more than 4 bytes, but let's
          // go for 8.
          char buffer[8];
          const int num_bytes = fz_runetochar(buffer, c);
          assert(num_bytes <= static_cast<int>(sizeof(buffer)));
          buffer[num_bytes] = '\0';
          r += buffer;
        }
      }
      if (!isspace(r.back())) {
        r += line_sep;
      }
    }
  }

  // 4. Clean up.
  fz_drop_stext_page(_fz_context, text_page);
  fz_drop_stext_sheet(_fz_context, text_sheet);

  return r;
}
Beispiel #9
0
std::string PDFDocument::GetPageText(int page, int line_sep) {
  // 1. Init MuPDF structures.
  pdf_page* page_struct = GetPage(page);

#if MUPDF_VERSION < 10012
  fz_stext_sheet* text_sheet = fz_new_stext_sheet(_fz_context);
#endif

  // 2. Render page.
#if MUPDF_VERSION >= 10012
  fz_stext_options stext_options = {0};
  // See #elif MUPDF_VERSION >= 10009 block below.
  fz_stext_page* text_page = fz_new_stext_page_from_page(
      _fz_context, &(page_struct->super), &stext_options);
#elif MUPDF_VERSION >= 10010
  fz_stext_options stext_options = {0};
  // See #elif MUPDF_VERSION >= 10009 block below.
  fz_stext_page* text_page = fz_new_stext_page_from_page(
      _fz_context, &(page_struct->super), text_sheet, &stext_options);
#elif MUPDF_VERSION >= 10009
  // The function below is a wrapper around fz_run_page that uses a fresh
  // device. We can't use pdf_run_page to gather the text for us.
  // These notes are also left in here in case MuPDF's API changes again.
  fz_stext_page* text_page = fz_new_stext_page_from_page(
      _fz_context, &(page_struct->super), text_sheet);
#else
  fz_stext_page* text_page = fz_new_text_page(_fz_context);
  fz_device* dev = fz_new_stext_device(_fz_context, text_sheet, text_page);
  // I've no idea what fz_{begin,end}_page do, but without them pdf_run_page
  // segfaults :-/
  fz_begin_page(_fz_context, dev, &fz_infinite_rect, &fz_identity);
  pdf_run_page(
      _fz_context, _pdf_document, page_struct, dev, &fz_identity, nullptr);
  fz_end_page(_fz_context, dev);
#endif

  // 3. Build text.
  std::string r;
#if MUPDF_VERSION >= 10012
  for (fz_stext_block* text_block = text_page->first_block;
       text_block != nullptr; text_block = text_block->next) {
    if (text_block->type != FZ_STEXT_BLOCK_TEXT) {
      continue;
    }
    for (fz_stext_line* text_line = text_block->u.t.first_line;
         text_line != nullptr; text_line = text_line->next) {
      for (fz_stext_char* text_char = text_line->first_char;
           text_char != nullptr; text_char = text_char->next) {
        {
          const int c = text_char->c;
#else
  for (fz_page_block* page_block = text_page->blocks;
       page_block < text_page->blocks + text_page->len; ++page_block) {
    assert(page_block != nullptr);
    if (page_block->type != FZ_PAGE_BLOCK_TEXT) {
      continue;
    }
    fz_stext_block* const text_block = page_block->u.text;
    assert(text_block != nullptr);
    for (fz_stext_line* text_line = text_block->lines;
         text_line < text_block->lines + text_block->len; ++text_line) {
      assert(text_line != nullptr);
      for (fz_stext_span* text_span = text_line->first_span;
           text_span != nullptr; text_span = text_span->next) {
        for (int i = 0; i < text_span->len; ++i) {
          const int c = text_span->text[i].c;
#endif
          // A single UTF-8 character cannot take more than 4 bytes, but let's
          // go for 8.
          char buffer[8];
          const int num_bytes = fz_runetochar(buffer, c);
          assert(num_bytes <= static_cast<int>(sizeof(buffer)));
          buffer[num_bytes] = '\0';
          r += buffer;
        }
      }
      if (!isspace(r.back())) {
        r += line_sep;
      }
    }
  }

  // 4. Clean up.
  fz_drop_stext_page(_fz_context, text_page);
#if MUPDF_VERSION < 10012
  fz_drop_stext_sheet(_fz_context, text_sheet);
#endif

  return r;
}

PDFDocument::PDFOutlineItem::~PDFOutlineItem() {}

PDFDocument::PDFOutlineItem::PDFOutlineItem(fz_outline* src) {
  if (src == nullptr) {
    _dest_page = -1;
  } else {
    _title = src->title;
#if MUPDF_VERSION >= 10010
    _dest_page = src->page;
#else
    _dest_page = src->dest.ld.gotor.page;
#endif
  }
}

int PDFDocument::PDFOutlineItem::GetDestPage() const { return _dest_page; }

PDFDocument::PDFOutlineItem* PDFDocument::PDFOutlineItem::Build(
    fz_context* ctx, fz_outline* src) {
  PDFOutlineItem* root = nullptr;
  std::vector<std::unique_ptr<OutlineItem>> items;
  BuildRecursive(src, &items);
  fz_drop_outline(ctx, src);
  if (items.empty()) {
    return nullptr;
  } else if (items.size() == 1) {
    root = dynamic_cast<PDFOutlineItem*>(items[0].release());
  } else {
    root = new PDFOutlineItem(nullptr);
    root->_title = DEFAULT_ROOT_OUTLINE_ITEM_TITLE;
    root->_children.swap(items);
  }
  return root;
}

void PDFDocument::PDFOutlineItem::BuildRecursive(
    fz_outline* src,
    std::vector<std::unique_ptr<Document::OutlineItem>>* output) {
  assert(output != nullptr);
  for (fz_outline* i = src; i != nullptr; i = i->next) {
    PDFOutlineItem* item = new PDFOutlineItem(i);
    if (i->down != nullptr) {
      BuildRecursive(i->down, &(item->_children));
    }
    output->push_back(std::unique_ptr<Document::OutlineItem>(item));
  }
}

PDFDocument::PDFPageCache::PDFPageCache(int cache_size, PDFDocument* parent)
    : Cache<int, pdf_page*>(cache_size), _parent(parent) {}

PDFDocument::PDFPageCache::~PDFPageCache() { Clear(); }

pdf_page* PDFDocument::PDFPageCache::Load(const int& page) {
  std::unique_lock<std::mutex> lock(_mutex);
  return pdf_load_page(_parent->_fz_context, _parent->_pdf_document, page);
}

void PDFDocument::PDFPageCache::Discard(
    const int& page, pdf_page* const& page_struct) {
  std::unique_lock<std::mutex> lock(_mutex);
  pdf_drop_page(_parent->_fz_context, _parent->_pdf_document, page_struct);
}