2014-09-29 73 views
0

我正在開發一個使用vudroid的android項目,該項目又使用了mupdf版本0.5。mupdf渲染jpeg2000失去顏色?

Vudroid刪除了mupdf的原始openjpeg支持,我移植了mupdf 1.5版的openjpeg支持。

但我遇到了一個新問題,在JPX圖像色彩信息不見了,預期的效果enter image description here

我的效果: enter image description

停靠的負載JPX代碼:

#include "fitz.h" 
#include "mupdf.h" 

/* Without the definition of OPJ_STATIC, compilation fails on windows 
* due to the use of __stdcall. We believe it is required on some 
* linux toolchains too. */ 
#define OPJ_STATIC 
#ifndef _MSC_VER 
#define OPJ_HAVE_STDINT_H 
#endif 

#include <openjpeg.h> 

static void fz_opj_error_callback(const char *msg, void *client_data) 
{ 
    //fz_context *ctx = (fz_context *)client_data; 
    //fz_warn(ctx, "openjpeg error: %s", msg); 
} 

static void fz_opj_warning_callback(const char *msg, void *client_data) 
{ 
    //fz_context *ctx = (fz_context *)client_data; 
    //fz_warn(ctx, "openjpeg warning: %s", msg); 
} 

static void fz_opj_info_callback(const char *msg, void *client_data) 
{ 
    /* fz_warn("openjpeg info: %s", msg); */ 
} 

typedef struct stream_block_s 
{ 
    unsigned char *data; 
    int size; 
    int pos; 
} stream_block; 

static OPJ_SIZE_T fz_opj_stream_read(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) 
{ 
    stream_block *sb = (stream_block *)p_user_data; 
    int len; 

    len = sb->size - sb->pos; 
    if (len < 0) 
     len = 0; 
    if (len == 0) 
     return (OPJ_SIZE_T)-1; /* End of file! */ 
    if ((OPJ_SIZE_T)len > p_nb_bytes) 
     len = p_nb_bytes; 
    memcpy(p_buffer, sb->data + sb->pos, len); 
    sb->pos += len; 
    return len; 
} 

static OPJ_OFF_T fz_opj_stream_skip(OPJ_OFF_T skip, void * p_user_data) 
{ 
    stream_block *sb = (stream_block *)p_user_data; 

    if (skip > sb->size - sb->pos) 
     skip = sb->size - sb->pos; 
    sb->pos += skip; 
    return sb->pos; 
} 

static OPJ_BOOL fz_opj_stream_seek(OPJ_OFF_T seek_pos, void * p_user_data) 
{ 
    stream_block *sb = (stream_block *)p_user_data; 

    if (seek_pos > sb->size) 
     return OPJ_FALSE; 
    sb->pos = seek_pos; 
    return OPJ_TRUE; 
} 

fz_error 
fz_load_jpx(pdf_image* img, unsigned char *data, int size, fz_colorspace *defcs, int indexed) 
{ 
    //fz_pixmap *img; 
    opj_dparameters_t params; 
    opj_codec_t *codec; 
    opj_image_t *jpx; 
    opj_stream_t *stream; 
    fz_colorspace *colorspace; 
    unsigned char *p; 
    OPJ_CODEC_FORMAT format; 
    int a, n, w, h, depth, sgnd; 
    int x, y, k, v; 
    stream_block sb; 

    if (size < 2) 
     fz_throw("not enough data to determine image format"); 

    /* Check for SOC marker -- if found we have a bare J2K stream */ 
    if (data[0] == 0xFF && data[1] == 0x4F) 
     format = OPJ_CODEC_J2K; 
    else 
     format = OPJ_CODEC_JP2; 

    opj_set_default_decoder_parameters(&params); 
    if (indexed) 
     params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; 

    codec = opj_create_decompress(format); 
    opj_set_info_handler(codec, fz_opj_info_callback, 0); 
    opj_set_warning_handler(codec, fz_opj_warning_callback, 0); 
    opj_set_error_handler(codec, fz_opj_error_callback, 0); 
    if (!opj_setup_decoder(codec, &params)) 
    { 
     fz_throw("j2k decode failed"); 
    } 

    stream = opj_stream_default_create(OPJ_TRUE); 
    sb.data = data; 
    sb.pos = 0; 
    sb.size = size; 

    opj_stream_set_read_function(stream, fz_opj_stream_read); 
    opj_stream_set_skip_function(stream, fz_opj_stream_skip); 
    opj_stream_set_seek_function(stream, fz_opj_stream_seek); 
    opj_stream_set_user_data(stream, &sb); 
    /* Set the length to avoid an assert */ 
    opj_stream_set_user_data_length(stream, size); 

    if (!opj_read_header(stream, codec, &jpx)) 
    { 
     opj_stream_destroy(stream); 
     opj_destroy_codec(codec); 
     fz_throw("Failed to read JPX header"); 
    } 

    if (!opj_decode(codec, stream, jpx)) 
    { 
     opj_stream_destroy(stream); 
     opj_destroy_codec(codec); 
     opj_image_destroy(jpx); 
     fz_throw("Failed to decode JPX image"); 
    } 

    opj_stream_destroy(stream); 
    opj_destroy_codec(codec); 

    /* jpx should never be NULL here, but check anyway */ 
    if (!jpx) 
     fz_throw("opj_decode failed"); 

    pdf_logimage("opj_decode succeeded"); 

    for (k = 1; k < (int)jpx->numcomps; k++) 
    { 
     if (!jpx->comps[k].data) 
     { 
      opj_image_destroy(jpx); 
      fz_throw("image components are missing data"); 
     } 
     if (jpx->comps[k].w != jpx->comps[0].w) 
     { 
      opj_image_destroy(jpx); 
      fz_throw("image components have different width"); 
     } 
     if (jpx->comps[k].h != jpx->comps[0].h) 
     { 
      opj_image_destroy(jpx); 
      fz_throw("image components have different height"); 
     } 
     if (jpx->comps[k].prec != jpx->comps[0].prec) 
     { 
      opj_image_destroy(jpx); 
      fz_throw("image components have different precision"); 
     } 
    } 

    n = jpx->numcomps; 
    w = jpx->comps[0].w; 
    h = jpx->comps[0].h; 
    depth = jpx->comps[0].prec; 
    sgnd = jpx->comps[0].sgnd; 

    if (jpx->color_space == OPJ_CLRSPC_SRGB && n == 4) { n = 3; a = 1; } 
    else if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 4) { n = 3; a = 1; } 
    else if (n == 2) { n = 1; a = 1; } 
    else if (n > 4) { n = 4; a = 1; } 
    else { a = 0; } 

    if (defcs) 
    { 
     if (defcs->n == n) 
     { 
      colorspace = defcs; 
     } 
     else 
     { 
      fz_warn("jpx file and dict colorspaces do not match"); 
      defcs = NULL; 
     } 
    } 

    if (!defcs) 
    { 
     switch (n) 
     { 
      case 1: colorspace = pdf_devicegray; break; 
      case 3: colorspace = pdf_devicergb; break; 
      case 4: colorspace = pdf_devicecmyk; break; 
     } 
    } 

    //error = fz_new_pixmap(&img, colorspace, w, h); 
    //if (error) 
    // return error; 

    pdf_logimage("colorspace handled\n"); 

    int bpc = 1; 
    if (colorspace) { 
     bpc = 1 + colorspace->n; 
    }; 
    pdf_logimage("w = %d, bpc = %d, h = %d\n", w, bpc, h); 
    img->samples = fz_newbuffer(w * bpc * h); 

    //opj_image_destroy(jpx); 
    //fz_throw("out of memory loading jpx"); 
    p = (char*)img->samples->bp; 
    pdf_logimage("start to deal with samples"); 
    for (y = 0; y < h; y++) 
    { 
     for (x = 0; x < w; x++) 
     { 
      for (k = 0; k < n + a; k++) 
      { 
       v = jpx->comps[k].data[y * w + x]; 
       if (sgnd) 
        v = v + (1 << (depth - 1)); 
       if (depth > 8) 
        v = v >> (depth - 8); 
       *p++ = v; 
      } 
      if (!a) 
       *p++ = 255; 
     } 
    } 
    img->samples->wp = p; 

    pdf_logimage("start to deal with samples succeeded"); 
    opj_image_destroy(jpx); 

// if (a) 
// { 
//  if (n == 4) 
//  { 
//   fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), w, h); 
//   fz_convert_pixmap(ctx, tmp, img); 
//   fz_drop_pixmap(ctx, img); 
//   img = tmp; 
//  } 
//  fz_premultiply_pixmap(ctx, img); 
// } 
    return fz_okay; 
} 

渲染代碼:

JNIEXPORT jbyteArray JNICALL Java_org_vudroid_pdfdroid_codec_PdfPage_drawPage 
    (JNIEnv *env, jclass clazz, jlong dochandle, jlong pagehandle) 
{ 
    renderdocument_t *doc = (renderdocument_t*) dochandle; 
    renderpage_t *page = (renderpage_t*) pagehandle; 

    //DEBUG("PdfView(%p).drawpage(%p, %p)", this, doc, page); 

    fz_error error; 
    fz_matrix ctm; 
    fz_irect viewbox; 
    fz_pixmap *pixmap; 
    jfloat *matrix; 
    jint *viewboxarr; 
    jint *dimen; 
    jint *buffer; 
    int length, val; 

    pixmap = nil; 

    /* initialize parameter arrays for MuPDF */ 

    ctm.a = 1; 
    ctm.b = 0; 
    ctm.c = 0; 
    ctm.d = 1; 
    ctm.e = 0; 
    ctm.f = 0; 

// matrix = (*env)->GetPrimitiveArrayCritical(env, matrixarray, 0); 
// ctm.a = matrix[0]; 
// ctm.b = matrix[1]; 
// ctm.c = matrix[2]; 
// ctm.d = matrix[3]; 
// ctm.e = matrix[4]; 
// ctm.f = matrix[5]; 
// (*env)->ReleasePrimitiveArrayCritical(env, matrixarray, matrix, 0); 
// DEBUG("Matrix: %f %f %f %f %f %f", 
//   ctm.a, ctm.b, ctm.c, ctm.d, ctm.e, ctm.f); 

// viewboxarr = (*env)->GetPrimitiveArrayCritical(env, viewboxarray, 0); 
// viewbox.x0 = viewboxarr[0]; 
// viewbox.y0 = viewboxarr[1]; 
// viewbox.x1 = viewboxarr[2]; 
// viewbox.y1 = viewboxarr[3]; 
// (*env)->ReleasePrimitiveArrayCritical(env, viewboxarray, viewboxarr, 0); 
// DEBUG("Viewbox: %d %d %d %d", 
//   viewbox.x0, viewbox.y0, viewbox.x1, viewbox.y1); 
    viewbox.x0 = 0; 
    viewbox.y0 = 0; 
    viewbox.x1 = 595; 
    viewbox.y1 = 841; 

    /* do the rendering */ 
    DEBUG("doing the rendering..."); 
    //buffer = (*env)->GetPrimitiveArrayCritical(env, bufferarray, 0); 

    // do the actual rendering: 
    error = fz_rendertree(&pixmap, doc->rast, page->page->tree, 
      ctm, viewbox, 1); 

    /* evil magic: we transform the rendered image's byte order 
    */ 
    int x, y; 

    if (bmpdata) 
     fz_free(bmpdata); 

    bmpstride = ((pixmap->w * 3 + 3)/4) * 4; 
    bmpdata = fz_malloc(pixmap->h * bmpstride); 
    DEBUG("inside drawpage, bmpstride = %d, pixmap->w = %d, pixmap->h = %d\n", bmpstride, pixmap->w, pixmap->h); 
    if (!bmpdata) 
     return; 

    for (y = 0; y < pixmap->h; y++) 
    { 
     unsigned char *p = bmpdata + y * bmpstride; 
     unsigned char *s = pixmap->samples + y * pixmap->w * 4; 
     for (x = 0; x < pixmap->w; x++) 
     { 
      p[x * 3 + 0] = s[x * 4 + 3]; 
      p[x * 3 + 1] = s[x * 4 + 2]; 
      p[x * 3 + 2] = s[x * 4 + 1]; 
     } 
    } 

    FILE* fp = fopen("/sdcard/drawpage", "wb"); 
    fwrite(bmpdata, pixmap->h * bmpstride, 1, fp); 
    fclose(fp); 

    jbyteArray array = (*env)->NewByteArray(env, pixmap->h * bmpstride); 
    (*env)->SetByteArrayRegion(env, array, 0, pixmap->h * bmpstride, bmpdata); 

// if(!error) { 
//  DEBUG("Converting image buffer pixel order"); 
//  length = pixmap->w * pixmap->h; 
//  unsigned int *col = pixmap->samples; 
//  int c = 0; 
//  for(val = 0; val < length; val++) { 
//   col[val] = ((col[val] & 0xFF000000) >> 24) | 
//     ((col[val] & 0x00FF0000) >> 8) | 
//     ((col[val] & 0x0000FF00) << 8); 
//  } 
//  winconvert(pixmap); 
// } 

// (*env)->ReleasePrimitiveArrayCritical(env, bufferarray, buffer, 0); 

    fz_free(pixmap); 

    if (error) { 
     DEBUG("error!"); 
     throw_exception(env, "error rendering page"); 
    } 

    DEBUG("PdfView.drawPage() done"); 
    return array; 
} 

我已經比較了jpx輸出樣本到mupdf-1.5窗口,它是一樣的,但原始jpx的顏色空間已經消失。

可以幫助我獲得色彩空間嗎?

回答

1

看來你正在嘗試使用一箇舊版本的MuPDF,其中一些位是從更新的版本中提取的。說實話,這是不太可能的工作。我也猜測它不是OpenJPEG庫引起你的問題,因爲圖像出現,但轉換爲灰度。

您是否嘗試過在當前版本的MuPDF中打開該文件?它工作嗎?

如果是這樣,那麼在我看來,你的正確方法應該是使用當前的代碼,而不是嘗試和螺栓上的舊版本。

+0

mupdf的新版本和舊版本都可以正確呈現pdf。 – Jichao 2014-09-29 07:38:57

+0

如果MuPDF 0.5可以正確渲染文件,那麼它會在MuPDF之外進行猜測。應用程序使用MuPDF的方式。 – KenS 2014-09-29 10:48:47