image.c 3.6 KB
Newer Older
1 2 3 4 5 6 7
/* See LICENSE file for license and copyright information */

#include <glib.h>
#include <girara/datastructures.h>
#include <mupdf/pdf.h>

#include "plugin.h"
8
#include "utils.h"
9 10 11 12

static void pdf_zathura_image_free(zathura_image_t* image);

girara_list_t*
13
pdf_page_images_get(zathura_page_t* page, void* data, zathura_error_t* error)
14
{
15 16
  mupdf_page_t* mupdf_page = data;

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
  if (page == NULL) {
    if (error != NULL) {
      *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
    }
    goto error_ret;
  }

  girara_list_t* list = NULL;
  zathura_document_t* document = zathura_page_get_document(page);
  if (document == NULL) {
    goto error_ret;
  }

  mupdf_document_t* mupdf_document = zathura_document_get_data(document);

32
  /* Setup image list */
33 34 35 36 37 38 39 40 41 42
  list = girara_list_new();
  if (list == NULL) {
    if (error != NULL) {
      *error = ZATHURA_ERROR_OUT_OF_MEMORY;
    }
    goto error_free;
  }

  girara_list_set_free_function(list, (girara_free_function_t) pdf_zathura_image_free);

43 44 45
  /* Extract images */
  mupdf_page_extract_text(mupdf_document, mupdf_page);

Pavel Vinogradov's avatar
Pavel Vinogradov committed
46 47 48
  fz_stext_block* block;
  for (block = mupdf_page->text->first_block; block; block = block->next) {
    if (block->type == FZ_STEXT_BLOCK_IMAGE) {
49 50
      zathura_image_t* zathura_image = g_malloc(sizeof(zathura_image_t));

Pavel Vinogradov's avatar
Pavel Vinogradov committed
51 52 53 54 55
      zathura_image->position.x1 = block->bbox.x0;
      zathura_image->position.y1 = block->bbox.y0;
      zathura_image->position.x2 = block->bbox.x1;
      zathura_image->position.y2 = block->bbox.y1;
      zathura_image->data        = block->u.i.image;
56 57 58 59

      girara_list_append(list, zathura_image);
    }
  }
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

  return list;

error_free:

  if (error != NULL && *error == ZATHURA_ERROR_OK) {
    *error = ZATHURA_ERROR_UNKNOWN;
  }

  if (list != NULL) {
    girara_list_free(list);
  }

error_ret:

  return NULL;
}

78
cairo_surface_t*
79
pdf_page_image_get_cairo(zathura_page_t* page, void* data,
80
    zathura_image_t* image, zathura_error_t* error)
81
{
82 83
  mupdf_page_t* mupdf_page = data;

84 85 86 87 88
  if (page == NULL || mupdf_page == NULL || image == NULL || image->data == NULL) {
    if (error != NULL) {
      *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
    }
    goto error_ret;
89 90
  }

91
  fz_image* mupdf_image = (fz_image*) image->data;
92

93 94
  fz_pixmap* pixmap = NULL;
  cairo_surface_t* surface = NULL;
95

Moritz Lipp's avatar
Moritz Lipp committed
96
  pixmap = fz_get_pixmap_from_image(mupdf_page->ctx, mupdf_image, NULL, NULL, 0, 0);
97 98
  if (pixmap == NULL) {
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
99 100
  }

101 102 103
  surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, mupdf_image->w, mupdf_image->h);
  if (surface == NULL) {
    goto error_free;
Moritz Lipp's avatar
Moritz Lipp committed
104 105
  }

106 107
  unsigned char* surface_data = cairo_image_surface_get_data(surface);
  int rowstride = cairo_image_surface_get_stride(surface);
Moritz Lipp's avatar
Moritz Lipp committed
108

109 110
  unsigned char* s = fz_pixmap_samples(mupdf_page->ctx, pixmap);
  unsigned int n   = fz_pixmap_components(mupdf_page->ctx, pixmap);
111

Sebastian Ramacher's avatar
Sebastian Ramacher committed
112 113 114 115
  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++) {
116
      guchar* p = surface_data + y * rowstride + x * 4;
117

118 119 120 121 122 123 124 125 126 127
      // 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];
128
      }
129
      s += n;
130
    }
131
  }
132

133
  fz_drop_pixmap(mupdf_page->ctx, pixmap);
134

135
  return surface;
136

137
error_free:
138

139 140
  if (pixmap != NULL) {
    fz_drop_pixmap(mupdf_page->ctx, pixmap);
141 142
  }

143 144
  if (surface != NULL) {
    cairo_surface_destroy(surface);
Moritz Lipp's avatar
Moritz Lipp committed
145 146
  }

147
error_ret:
Moritz Lipp's avatar
Moritz Lipp committed
148

149 150
  return NULL;
}
Moritz Lipp's avatar
Moritz Lipp committed
151

152 153 154 155
static void
pdf_zathura_image_free(zathura_image_t* image)
{
  if (image == NULL) {
156 157 158
    return;
  }

159
  g_free(image);
160
}