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

#define _POSIX_C_SOURCE 1

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

#include "plugin.h"
10
#include "utils.h"
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

static void pdf_zathura_image_free(zathura_image_t* image);

girara_list_t*
pdf_page_images_get(zathura_page_t* page, mupdf_page_t* mupdf_page, zathura_error_t* error)
{
  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 79 80
cairo_surface_t*
pdf_page_image_get_cairo(zathura_page_t* page, mupdf_page_t* mupdf_page,
    zathura_image_t* image, zathura_error_t* error)
81
{
82 83 84 85 86
  if (page == NULL || mupdf_page == NULL || image == NULL || image->data == NULL) {
    if (error != NULL) {
      *error = ZATHURA_ERROR_INVALID_ARGUMENTS;
    }
    goto error_ret;
87 88
  }

89
  fz_image* mupdf_image = (fz_image*) image->data;
90

91 92
  fz_pixmap* pixmap = NULL;
  cairo_surface_t* surface = NULL;
93

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

99 100 101
  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
102 103
  }

104 105
  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
106

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

110 111 112
  for (unsigned int y = 0; y < fz_pixmap_height(mupdf_page->ctx, pixmap); y++) {
    for (unsigned int x = 0; x < fz_pixmap_width(mupdf_page->ctx, pixmap); x++) {
      guchar* p = surface_data + y * rowstride + x * 4;
113

114 115 116 117 118 119 120 121 122 123
      // 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];
124
      }
125
      s += n;
126
    }
127
  }
128

129
  fz_drop_pixmap(mupdf_page->ctx, pixmap);
130

131
  return surface;
132

133
error_free:
134

135 136
  if (pixmap != NULL) {
    fz_drop_pixmap(mupdf_page->ctx, pixmap);
137 138
  }

139 140
  if (surface != NULL) {
    cairo_surface_destroy(surface);
Moritz Lipp's avatar
Moritz Lipp committed
141 142
  }

143
error_ret:
Moritz Lipp's avatar
Moritz Lipp committed
144

145 146
  return NULL;
}
Moritz Lipp's avatar
Moritz Lipp committed
147

148 149 150 151
static void
pdf_zathura_image_free(zathura_image_t* image)
{
  if (image == NULL) {
152 153 154
    return;
  }

155
  g_free(image);
156
}