michael@0: /* michael@0: * Copyright 2010 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkJpegUtility.h" michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: static void sk_init_source(j_decompress_ptr cinfo) { michael@0: skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src; michael@0: src->next_input_byte = (const JOCTET*)src->fBuffer; michael@0: src->bytes_in_buffer = 0; michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: src->current_offset = 0; michael@0: #endif michael@0: if (!src->fStream->rewind()) { michael@0: SkDebugf("xxxxxxxxxxxxxx failure to rewind\n"); michael@0: cinfo->err->error_exit((j_common_ptr)cinfo); michael@0: } michael@0: } michael@0: michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: static boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) { michael@0: skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src; michael@0: size_t bo = (size_t) byte_offset; michael@0: michael@0: if (bo > src->current_offset) { michael@0: (void)src->fStream->skip(bo - src->current_offset); michael@0: } else { michael@0: if (!src->fStream->rewind()) { michael@0: SkDebugf("xxxxxxxxxxxxxx failure to rewind\n"); michael@0: cinfo->err->error_exit((j_common_ptr)cinfo); michael@0: return false; michael@0: } michael@0: (void)src->fStream->skip(bo); michael@0: } michael@0: michael@0: src->current_offset = bo; michael@0: src->next_input_byte = (const JOCTET*)src->fBuffer; michael@0: src->bytes_in_buffer = 0; michael@0: return true; michael@0: } michael@0: #endif michael@0: michael@0: static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) { michael@0: skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src; michael@0: if (src->fDecoder != NULL && src->fDecoder->shouldCancelDecode()) { michael@0: return FALSE; michael@0: } michael@0: size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize); michael@0: // note that JPEG is happy with less than the full read, michael@0: // as long as the result is non-zero michael@0: if (bytes == 0) { michael@0: return FALSE; michael@0: } michael@0: michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: src->current_offset += bytes; michael@0: #endif michael@0: src->next_input_byte = (const JOCTET*)src->fBuffer; michael@0: src->bytes_in_buffer = bytes; michael@0: return TRUE; michael@0: } michael@0: michael@0: static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { michael@0: skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src; michael@0: michael@0: if (num_bytes > (long)src->bytes_in_buffer) { michael@0: size_t bytesToSkip = num_bytes - src->bytes_in_buffer; michael@0: while (bytesToSkip > 0) { michael@0: size_t bytes = src->fStream->skip(bytesToSkip); michael@0: if (bytes <= 0 || bytes > bytesToSkip) { michael@0: // SkDebugf("xxxxxxxxxxxxxx failure to skip request %d returned %d\n", bytesToSkip, bytes); michael@0: cinfo->err->error_exit((j_common_ptr)cinfo); michael@0: return; michael@0: } michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: src->current_offset += bytes; michael@0: #endif michael@0: bytesToSkip -= bytes; michael@0: } michael@0: src->next_input_byte = (const JOCTET*)src->fBuffer; michael@0: src->bytes_in_buffer = 0; michael@0: } else { michael@0: src->next_input_byte += num_bytes; michael@0: src->bytes_in_buffer -= num_bytes; michael@0: } michael@0: } michael@0: michael@0: static void sk_term_source(j_decompress_ptr /*cinfo*/) {} michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder) michael@0: : fStream(SkRef(stream)) michael@0: , fDecoder(decoder) { michael@0: michael@0: init_source = sk_init_source; michael@0: fill_input_buffer = sk_fill_input_buffer; michael@0: skip_input_data = sk_skip_input_data; michael@0: resync_to_restart = jpeg_resync_to_restart; michael@0: term_source = sk_term_source; michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: seek_input_data = sk_seek_input_data; michael@0: #endif michael@0: // SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize); michael@0: } michael@0: michael@0: skjpeg_source_mgr::~skjpeg_source_mgr() { michael@0: SkSafeUnref(fStream); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static void sk_init_destination(j_compress_ptr cinfo) { michael@0: skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest; michael@0: michael@0: dest->next_output_byte = dest->fBuffer; michael@0: dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize; michael@0: } michael@0: michael@0: static boolean sk_empty_output_buffer(j_compress_ptr cinfo) { michael@0: skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest; michael@0: michael@0: // if (!dest->fStream->write(dest->fBuffer, skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer)) michael@0: if (!dest->fStream->write(dest->fBuffer, michael@0: skjpeg_destination_mgr::kBufferSize)) { michael@0: ERREXIT(cinfo, JERR_FILE_WRITE); michael@0: return false; michael@0: } michael@0: michael@0: dest->next_output_byte = dest->fBuffer; michael@0: dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize; michael@0: return TRUE; michael@0: } michael@0: michael@0: static void sk_term_destination (j_compress_ptr cinfo) { michael@0: skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest; michael@0: michael@0: size_t size = skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer; michael@0: if (size > 0) { michael@0: if (!dest->fStream->write(dest->fBuffer, size)) { michael@0: ERREXIT(cinfo, JERR_FILE_WRITE); michael@0: return; michael@0: } michael@0: } michael@0: dest->fStream->flush(); michael@0: } michael@0: michael@0: skjpeg_destination_mgr::skjpeg_destination_mgr(SkWStream* stream) michael@0: : fStream(stream) { michael@0: this->init_destination = sk_init_destination; michael@0: this->empty_output_buffer = sk_empty_output_buffer; michael@0: this->term_destination = sk_term_destination; michael@0: } michael@0: michael@0: void skjpeg_error_exit(j_common_ptr cinfo) { michael@0: skjpeg_error_mgr* error = (skjpeg_error_mgr*)cinfo->err; michael@0: michael@0: (*error->output_message) (cinfo); michael@0: michael@0: /* Let the memory manager delete any temp files before we die */ michael@0: jpeg_destroy(cinfo); michael@0: michael@0: longjmp(error->fJmpBuf, -1); michael@0: }