0

我正在开发一个使用 vudroid 的 android 项目,而 vudroid 又使用 mupdf 0.5 版。

Vudroid 去掉了原来对 mupdf 的 openjpeg 支持,我已经移植了 mupdf 1.5 版的 openjpeg 支持。

但是我遇到了一个新问题,jpx图像中的颜色信息没了,想要的效果在此处输入图像描述

我的效果: 输入图片描述

移植的 load-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 的色彩空间已经消失。

可以帮我找回色彩空间吗?

4

1 回答 1

1

看来您正在尝试使用旧版本的 MuPDF,其中一些位是从较新版本中提取的。老实说,这几乎不可能奏效。我还猜想它不是导致您的问题的 OpenJPEG 库,因为图像出现了,但已转换为灰度。

您是否尝试过在当前版本的 MuPDF 中打开文件?行得通吗?

如果是这样,那么在我看来,您的正确方法应该是使用当前代码,而不是尝试将部分固定到旧版本上。

于 2014-09-29T07:06:46.577 回答