diff --git a/libscan/ebook/ebook.c b/libscan/ebook/ebook.c index 67c0e90..4b9b0d6 100644 --- a/libscan/ebook/ebook.c +++ b/libscan/ebook/ebook.c @@ -1,9 +1,10 @@ #include "ebook.h" -#include "../util.h" #include #include #include +#include "../media/media.h" + #define MIN_OCR_SIZE 350 #define MIN_OCR_LEN 10 @@ -71,32 +72,61 @@ int render_cover(scan_ebook_ctx_t *ctx, fz_context *fzctx, document_t *doc, fz_d return -1; } - fz_buffer *fzbuf = NULL; - fz_var(fzbuf); - fz_var(err); - - fz_try(fzctx) - fzbuf = fz_new_buffer_from_pixmap_as_png(fzctx, pixmap, fz_default_color_params); - fz_catch(fzctx) - err = fzctx->error.errcode; - - if (err == 0) { - unsigned char *tn_buf; - size_t tn_len = fz_buffer_storage(fzctx, fzbuf, &tn_buf); - APPEND_TN_META(doc, pixmap->x, pixmap->y) - ctx->store((char *) doc->uuid, sizeof(doc->uuid), (char *) tn_buf, tn_len); - } - - fz_drop_buffer(fzctx, fzbuf); - fz_drop_pixmap(fzctx, pixmap); - fz_drop_page(fzctx, cover); - - if (err != 0) { - CTX_LOG_WARNINGF(doc->filepath, "fz_new_buffer_from_pixmap_as_png() returned error code [%d] %s", err, - fzctx->error.message) + if (pixmap->n != 3) { + CTX_LOG_ERRORF(doc->filepath, "Got unexpected pixmap depth: %d", pixmap->n) + fz_drop_page(fzctx, cover); + fz_drop_pixmap(fzctx, pixmap); return -1; } + // RGB24 -> YUV420p + AVFrame *scaled_frame = av_frame_alloc(); + + struct SwsContext *sws_ctx= sws_getContext( + pixmap->w, pixmap->h, AV_PIX_FMT_RGB24, + pixmap->w, pixmap->h, AV_PIX_FMT_YUVJ420P, + SIST_SWS_ALGO, 0, 0, 0 + ); + + int dst_buf_len = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pixmap->w, pixmap->h, 1); + uint8_t *dst_buf = (uint8_t *) av_malloc(dst_buf_len); + + av_image_fill_arrays(scaled_frame->data, scaled_frame->linesize, dst_buf, AV_PIX_FMT_YUV420P, pixmap->w, pixmap->h, 1); + + const uint8_t *in_data[1] = {pixmap->samples}; + int in_line_size[1] = {3 * pixmap->w}; + + sws_scale(sws_ctx, + in_data, in_line_size, + 0, pixmap->h, + scaled_frame->data, scaled_frame->linesize + ); + + scaled_frame->width = pixmap->w; + scaled_frame->height = pixmap->h; + scaled_frame->format = AV_PIX_FMT_YUV420P; + + sws_freeContext(sws_ctx); + + // YUV420p -> JPEG + AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(pixmap->w, pixmap->h, 1.0f); + avcodec_send_frame(jpeg_encoder, scaled_frame); + + AVPacket jpeg_packet; + av_init_packet(&jpeg_packet); + avcodec_receive_packet(jpeg_encoder, &jpeg_packet); + + APPEND_TN_META(doc, pixmap->w, pixmap->h) + ctx->store((char *) doc->uuid, sizeof(doc->uuid), (char *) jpeg_packet.data, jpeg_packet.size); + + av_packet_unref(&jpeg_packet); + av_free(*scaled_frame->data); + av_frame_free(&scaled_frame); + avcodec_free_context(&jpeg_encoder); + + fz_drop_pixmap(fzctx, pixmap); + fz_drop_page(fzctx, cover); + return 0; } diff --git a/libscan/media/media.c b/libscan/media/media.c index 242eb2d..411bc2c 100644 --- a/libscan/media/media.c +++ b/libscan/media/media.c @@ -2,11 +2,6 @@ #include "../util.h" -#include "libavformat/avformat.h" -#include "libswscale/swscale.h" -#include "libswresample/swresample.h" -#include "libavcodec/avcodec.h" -#include "libavutil/imgutils.h" #include @@ -15,28 +10,6 @@ #define IS_VIDEO(fmt) (fmt->iformat->name && strcmp(fmt->iformat->name, "image2") != 0) -__always_inline -static AVCodecContext *alloc_jpeg_encoder(scan_media_ctx_t *ctx, int dstW, int dstH, float qscale) { - - AVCodec *jpeg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); - AVCodecContext *jpeg = avcodec_alloc_context3(jpeg_codec); - jpeg->width = dstW; - jpeg->height = dstH; - jpeg->time_base.den = 1000000; - jpeg->time_base.num = 1; - jpeg->i_quant_factor = qscale; - - jpeg->pix_fmt = AV_PIX_FMT_YUVJ420P; - int ret = avcodec_open2(jpeg, jpeg_codec, NULL); - - if (ret != 0) { - CTX_LOG_WARNINGF("media.c", "Could not open jpeg encoder: %s!\n", av_err2str(ret)); - return NULL; - } - - return jpeg; -} - __always_inline AVFrame *scale_frame(const AVCodecContext *decoder, const AVFrame *frame, int size) { @@ -362,7 +335,7 @@ void parse_media_format_ctx(scan_media_ctx_t *ctx, AVFormatContext *pFormatCtx, } // Encode frame to jpeg - AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(ctx, scaled_frame->width, scaled_frame->height, + AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(scaled_frame->width, scaled_frame->height, ctx->tn_qscale); avcodec_send_frame(jpeg_encoder, scaled_frame); @@ -602,7 +575,7 @@ int store_image_thumbnail(scan_media_ctx_t *ctx, void* buf, size_t buf_len, docu } // Encode frame to jpeg - AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(ctx, scaled_frame->width, scaled_frame->height, ctx->tn_qscale); + AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(scaled_frame->width, scaled_frame->height, ctx->tn_qscale); avcodec_send_frame(jpeg_encoder, scaled_frame); AVPacket jpeg_packet; diff --git a/libscan/media/media.h b/libscan/media/media.h index 26091a0..8e77d52 100644 --- a/libscan/media/media.h +++ b/libscan/media/media.h @@ -4,6 +4,12 @@ #include "../scan.h" +#include "libavformat/avformat.h" +#include "libswscale/swscale.h" +#include "libswresample/swresample.h" +#include "libavcodec/avcodec.h" +#include "libavutil/imgutils.h" + typedef struct { log_callback_t log; logf_callback_t logf; @@ -14,6 +20,28 @@ typedef struct { long max_media_buffer; } scan_media_ctx_t; +__always_inline +static AVCodecContext *alloc_jpeg_encoder(int w, int h, float qscale) { + + AVCodec *jpeg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); + AVCodecContext *jpeg = avcodec_alloc_context3(jpeg_codec); + jpeg->width = w; + jpeg->height = h; + jpeg->time_base.den = 1000000; + jpeg->time_base.num = 1; + jpeg->i_quant_factor = qscale; + + jpeg->pix_fmt = AV_PIX_FMT_YUVJ420P; + int ret = avcodec_open2(jpeg, jpeg_codec, NULL); + + if (ret != 0) { + return NULL; + } + + return jpeg; +} + + void parse_media(scan_media_ctx_t *ctx, vfile_t *f, document_t *doc); void init_media(); diff --git a/libscan/raw/raw.c b/libscan/raw/raw.c index 995f79c..0239c6b 100644 --- a/libscan/raw/raw.c +++ b/libscan/raw/raw.c @@ -1,37 +1,8 @@ #include "raw.h" #include -#include -#include +#include "../media/media.h" -#include "libswscale/swscale.h" -#include "libswresample/swresample.h" -#include "libavcodec/avcodec.h" -#include "libavutil/imgutils.h" - - - -__always_inline -static AVCodecContext *alloc_jpeg_encoder(scan_raw_ctx_t *ctx, int dstW, int dstH, float qscale) { - - AVCodec *jpeg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); - AVCodecContext *jpeg = avcodec_alloc_context3(jpeg_codec); - jpeg->width = dstW; - jpeg->height = dstH; - jpeg->time_base.den = 1000000; - jpeg->time_base.num = 1; - jpeg->i_quant_factor = qscale; - - jpeg->pix_fmt = AV_PIX_FMT_YUVJ420P; - int ret = avcodec_open2(jpeg, jpeg_codec, NULL); - - if (ret != 0) { - CTX_LOG_WARNINGF("raw.c", "Could not open jpeg encoder: %s!\n", av_err2str(ret)) - return NULL; - } - - return jpeg; -} #define MIN_SIZE 32 @@ -152,11 +123,11 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) { av_image_fill_arrays(scaled_frame->data, scaled_frame->linesize, dst_buf, AV_PIX_FMT_YUV420P, dstW, dstH, 1); - const uint8_t *inData[1] = {img->data}; - int inLinesize[1] = {3 * img->width}; + const uint8_t *in_data[1] = {img->data}; + int in_line_size[1] = {3 * img->width}; sws_scale(sws_ctx, - inData, inLinesize, + in_data, in_line_size, 0, img->height, scaled_frame->data, scaled_frame->linesize ); @@ -167,7 +138,7 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) { sws_freeContext(sws_ctx); - AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(ctx, scaled_frame->width, scaled_frame->height, 1.0f); + AVCodecContext *jpeg_encoder = alloc_jpeg_encoder(scaled_frame->width, scaled_frame->height, 1.0f); avcodec_send_frame(jpeg_encoder, scaled_frame); AVPacket jpeg_packet; diff --git a/test/main.cpp b/test/main.cpp index 732e5f5..0ff2e42 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -174,12 +174,16 @@ TEST(Ebook, CandlePdf) { document_t doc; load_doc_file("libscan-test-files/test_files/ebook/General_-_Candle_Making.pdf", &f, &doc); + size_t size_before = store_size; + parse_ebook(&ebook_500_ctx, &f, "application/pdf", &doc); ASSERT_STREQ(get_meta(&doc, MetaTitle)->str_val, "Microsoft Word - A531 Candlemaking-01.doc"); ASSERT_STREQ(get_meta(&doc, MetaAuthor)->str_val, "Dafydd Prichard"); ASSERT_NEAR(strlen(get_meta(&doc, MetaContent)->str_val), 500, 4); ASSERT_NE(get_meta(&doc, MetaContent)->str_val[0], ' '); + ASSERT_NE(size_before, store_size); + cleanup(&doc, &f); }