109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com/*
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2010 The Android Open Source Project
309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com *
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com */
709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com#include "SkJpegUtility.h"
1009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
1109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com/////////////////////////////////////////////////////////////////////
1209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic void sk_init_source(j_decompress_ptr cinfo) {
1309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
1409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
1509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    src->bytes_in_buffer = 0;
164161fe6b4cd8ec008a8c5635bb631d5602668b81scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
177df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    src->current_offset = 0;
187df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com#endif
19fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com    src->fStream->rewind();
20fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com}
21fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com
224161fe6b4cd8ec008a8c5635bb631d5602668b81scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
237df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.comstatic boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
247df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
254ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com    size_t bo = (size_t) byte_offset;
267df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com
274ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com    if (bo > src->current_offset) {
284ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com        (void)src->fStream->skip(bo - src->current_offset);
297df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    } else {
307df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com        src->fStream->rewind();
314ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com        (void)src->fStream->skip(bo);
327df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    }
337df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com
344ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com    src->current_offset = bo;
357df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
367df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    src->bytes_in_buffer = 0;
377df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    return true;
387df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com}
397df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com#endif
407df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com
4109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
4209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
4309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    if (src->fDecoder != NULL && src->fDecoder->shouldCancelDecode()) {
4409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        return FALSE;
4509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    }
4609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
4709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    // note that JPEG is happy with less than the full read,
4809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    // as long as the result is non-zero
4909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    if (bytes == 0) {
5009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        return FALSE;
5109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    }
5209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
534161fe6b4cd8ec008a8c5635bb631d5602668b81scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
547df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    src->current_offset += bytes;
557df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com#endif
5609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
5709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    src->bytes_in_buffer = bytes;
5809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    return TRUE;
5909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
6009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
6109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
6209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
6309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
64dcfc89cccfe82f8099ef32170d352edba9778b0freed@android.com    if (num_bytes > (long)src->bytes_in_buffer) {
659c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com        long bytesToSkip = num_bytes - src->bytes_in_buffer;
669c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com        while (bytesToSkip > 0) {
679c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com            long bytes = (long)src->fStream->skip(bytesToSkip);
689c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com            if (bytes <= 0 || bytes > bytesToSkip) {
699c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com//              SkDebugf("xxxxxxxxxxxxxx failure to skip request %d returned %d\n", bytesToSkip, bytes);
709c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com                cinfo->err->error_exit((j_common_ptr)cinfo);
719c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com                return;
729c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com            }
734161fe6b4cd8ec008a8c5635bb631d5602668b81scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
747df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com            src->current_offset += bytes;
757df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com#endif
769c02ab1cf9e1e61b0f4ba217bf58634511cc5839reed@android.com            bytesToSkip -= bytes;
7709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        }
7809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        src->next_input_byte = (const JOCTET*)src->fBuffer;
7909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        src->bytes_in_buffer = 0;
8009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    } else {
8109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        src->next_input_byte += num_bytes;
8209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        src->bytes_in_buffer -= num_bytes;
8309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    }
8409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
8509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
8609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic boolean sk_resync_to_restart(j_decompress_ptr cinfo, int desired) {
8709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
8809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
8909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    // what is the desired param for???
9009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
9109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    if (!src->fStream->rewind()) {
9209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
9309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        cinfo->err->error_exit((j_common_ptr)cinfo);
9409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        return FALSE;
9509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    }
9609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
9709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    src->bytes_in_buffer = 0;
9809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    return TRUE;
9909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
10009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
10109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic void sk_term_source(j_decompress_ptr /*cinfo*/) {}
10209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
10309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
10409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com///////////////////////////////////////////////////////////////////////////////
10509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
1064ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.comskjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder)
1074ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com    : fStream(SkRef(stream))
1084ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com    , fDecoder(decoder) {
109fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com
110fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com    init_source = sk_init_source;
111fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com    fill_input_buffer = sk_fill_input_buffer;
112fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com    skip_input_data = sk_skip_input_data;
113fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com    resync_to_restart = sk_resync_to_restart;
114fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com    term_source = sk_term_source;
1154161fe6b4cd8ec008a8c5635bb631d5602668b81scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
1167df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com    seek_input_data = sk_seek_input_data;
1177df632ab780d57e8bc7ac8f47beba1296c97345fdjsollen@google.com#endif
11809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com//    SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
11909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
12009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
121fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.comskjpeg_source_mgr::~skjpeg_source_mgr() {
1224ecddbdf09fa5a08eb8ad57288f53dc040ede8b3scroggo@google.com    SkSafeUnref(fStream);
123fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com}
124fb9a4ea68b33af97fd279cb238d738833f24614edjsollen@google.com
12509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com///////////////////////////////////////////////////////////////////////////////
12609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
12709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic void sk_init_destination(j_compress_ptr cinfo) {
12809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
12909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
13009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    dest->next_output_byte = dest->fBuffer;
13109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
13209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
13309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
13409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic boolean sk_empty_output_buffer(j_compress_ptr cinfo) {
13509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
13609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
13709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com//  if (!dest->fStream->write(dest->fBuffer, skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer))
13809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    if (!dest->fStream->write(dest->fBuffer,
13909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com            skjpeg_destination_mgr::kBufferSize)) {
14009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        ERREXIT(cinfo, JERR_FILE_WRITE);
14109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        return false;
14209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    }
14309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
14409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    dest->next_output_byte = dest->fBuffer;
14509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
14609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    return TRUE;
14709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
14809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
14909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comstatic void sk_term_destination (j_compress_ptr cinfo) {
15009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
15109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
15209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    size_t size = skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer;
15309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    if (size > 0) {
15409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        if (!dest->fStream->write(dest->fBuffer, size)) {
15509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com            ERREXIT(cinfo, JERR_FILE_WRITE);
15609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com            return;
15709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        }
15809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    }
15909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    dest->fStream->flush();
16009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
16109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
16209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comskjpeg_destination_mgr::skjpeg_destination_mgr(SkWStream* stream)
16309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com        : fStream(stream) {
16409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    this->init_destination = sk_init_destination;
16509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    this->empty_output_buffer = sk_empty_output_buffer;
16609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    this->term_destination = sk_term_destination;
16709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
16809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
16909ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.comvoid skjpeg_error_exit(j_common_ptr cinfo) {
17009ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    skjpeg_error_mgr* error = (skjpeg_error_mgr*)cinfo->err;
17109ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
17209ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    (*error->output_message) (cinfo);
17309ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
17409ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    /* Let the memory manager delete any temp files before we die */
17509ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    jpeg_destroy(cinfo);
17609ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com
17709ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com    longjmp(error->fJmpBuf, -1);
17809ed9d799dd9e5390de27d77563a336c6b0fcc19reed@android.com}
179