1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/codec/SkJpegCodec.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h" 11cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 12cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 13cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 14cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 15cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 16cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 17cb93a386Sopenharmony_ci#include "src/codec/SkJpegDecoderMgr.h" 18cb93a386Sopenharmony_ci#include "src/codec/SkParseEncodedOrigin.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci// stdio is needed for libjpeg-turbo 21cb93a386Sopenharmony_ci#include <stdio.h> 22cb93a386Sopenharmony_ci#include "src/codec/SkJpegUtility.h" 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci// This warning triggers false postives way too often in here. 25cb93a386Sopenharmony_ci#if defined(__GNUC__) && !defined(__clang__) 26cb93a386Sopenharmony_ci #pragma GCC diagnostic ignored "-Wclobbered" 27cb93a386Sopenharmony_ci#endif 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciextern "C" { 30cb93a386Sopenharmony_ci #include "jerror.h" 31cb93a386Sopenharmony_ci #include "jpeglib.h" 32cb93a386Sopenharmony_ci} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cibool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) { 35cb93a386Sopenharmony_ci constexpr uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; 36cb93a386Sopenharmony_ci return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig)); 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ciconst uint32_t kExifHeaderSize = 14; 40cb93a386Sopenharmony_ciconst uint32_t kExifMarker = JPEG_APP0 + 1; 41cb93a386Sopenharmony_ciconst uint32_t kApp3Marker = JPEG_APP0 + 3; 42cb93a386Sopenharmony_ciconst uint32_t kApp4Marker = JPEG_APP0 + 4; 43cb93a386Sopenharmony_ciconst uint32_t kApp5Marker = JPEG_APP0 + 5; 44cb93a386Sopenharmony_ciconst uint32_t kApp6Marker = JPEG_APP0 + 6; 45cb93a386Sopenharmony_ciconst uint32_t kApp7Marker = JPEG_APP0 + 7; 46cb93a386Sopenharmony_ciconst uint32_t kApp8Marker = JPEG_APP0 + 8; 47cb93a386Sopenharmony_ciconst uint32_t kApp9Marker = JPEG_APP0 + 9; 48cb93a386Sopenharmony_ciconst uint32_t kApp10Marker = JPEG_APP0 + 10; 49cb93a386Sopenharmony_ciconst uint32_t kApp11Marker = JPEG_APP0 + 11; 50cb93a386Sopenharmony_ciconst uint32_t kApp12Marker = JPEG_APP0 + 12; 51cb93a386Sopenharmony_ciconst uint32_t kApp13Marker = JPEG_APP0 + 13; 52cb93a386Sopenharmony_ciconst uint32_t kApp14Marker = JPEG_APP0 + 14; 53cb93a386Sopenharmony_ciconst uint32_t kApp15Marker = JPEG_APP0 + 15; 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_cistatic bool is_orientation_marker(jpeg_marker_struct* marker, SkEncodedOrigin* orientation) { 56cb93a386Sopenharmony_ci if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) { 57cb93a386Sopenharmony_ci return false; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci constexpr uint8_t kExifSig[] { 'E', 'x', 'i', 'f', '\0' }; 61cb93a386Sopenharmony_ci if (0 != memcmp(marker->data, kExifSig, sizeof(kExifSig))) { 62cb93a386Sopenharmony_ci return false; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci // Account for 'E', 'x', 'i', 'f', '\0', '<fill byte>'. 66cb93a386Sopenharmony_ci constexpr size_t kOffset = 6; 67cb93a386Sopenharmony_ci return SkParseEncodedOrigin(marker->data + kOffset, marker->data_length - kOffset, 68cb93a386Sopenharmony_ci orientation); 69cb93a386Sopenharmony_ci} 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_cistatic SkEncodedOrigin get_exif_orientation(jpeg_decompress_struct* dinfo) { 72cb93a386Sopenharmony_ci SkEncodedOrigin orientation; 73cb93a386Sopenharmony_ci for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) { 74cb93a386Sopenharmony_ci if (is_orientation_marker(marker, &orientation)) { 75cb93a386Sopenharmony_ci return orientation; 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci return kDefault_SkEncodedOrigin; 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_cistatic bool is_icc_marker(jpeg_marker_struct* marker) { 83cb93a386Sopenharmony_ci if (kICCMarker != marker->marker || marker->data_length < kICCMarkerHeaderSize) { 84cb93a386Sopenharmony_ci return false; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci return !memcmp(marker->data, kICCSig, sizeof(kICCSig)); 88cb93a386Sopenharmony_ci} 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci/* 91cb93a386Sopenharmony_ci * ICC profiles may be stored using a sequence of multiple markers. We obtain the ICC profile 92cb93a386Sopenharmony_ci * in two steps: 93cb93a386Sopenharmony_ci * (1) Discover all ICC profile markers and verify that they are numbered properly. 94cb93a386Sopenharmony_ci * (2) Copy the data from each marker into a contiguous ICC profile. 95cb93a386Sopenharmony_ci */ 96cb93a386Sopenharmony_cistatic std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(jpeg_decompress_struct* dinfo) 97cb93a386Sopenharmony_ci{ 98cb93a386Sopenharmony_ci // Note that 256 will be enough storage space since each markerIndex is stored in 8-bits. 99cb93a386Sopenharmony_ci jpeg_marker_struct* markerSequence[256]; 100cb93a386Sopenharmony_ci memset(markerSequence, 0, sizeof(markerSequence)); 101cb93a386Sopenharmony_ci uint8_t numMarkers = 0; 102cb93a386Sopenharmony_ci size_t totalBytes = 0; 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci // Discover any ICC markers and verify that they are numbered properly. 105cb93a386Sopenharmony_ci for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) { 106cb93a386Sopenharmony_ci if (is_icc_marker(marker)) { 107cb93a386Sopenharmony_ci // Verify that numMarkers is valid and consistent. 108cb93a386Sopenharmony_ci if (0 == numMarkers) { 109cb93a386Sopenharmony_ci numMarkers = marker->data[13]; 110cb93a386Sopenharmony_ci if (0 == numMarkers) { 111cb93a386Sopenharmony_ci SkCodecPrintf("ICC Profile Error: numMarkers must be greater than zero.\n"); 112cb93a386Sopenharmony_ci return nullptr; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci } else if (numMarkers != marker->data[13]) { 115cb93a386Sopenharmony_ci SkCodecPrintf("ICC Profile Error: numMarkers must be consistent.\n"); 116cb93a386Sopenharmony_ci return nullptr; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci // Verify that the markerIndex is valid and unique. Note that zero is not 120cb93a386Sopenharmony_ci // a valid index. 121cb93a386Sopenharmony_ci uint8_t markerIndex = marker->data[12]; 122cb93a386Sopenharmony_ci if (markerIndex == 0 || markerIndex > numMarkers) { 123cb93a386Sopenharmony_ci SkCodecPrintf("ICC Profile Error: markerIndex is invalid.\n"); 124cb93a386Sopenharmony_ci return nullptr; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci if (markerSequence[markerIndex]) { 127cb93a386Sopenharmony_ci SkCodecPrintf("ICC Profile Error: Duplicate value of markerIndex.\n"); 128cb93a386Sopenharmony_ci return nullptr; 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci markerSequence[markerIndex] = marker; 131cb93a386Sopenharmony_ci SkASSERT(marker->data_length >= kICCMarkerHeaderSize); 132cb93a386Sopenharmony_ci totalBytes += marker->data_length - kICCMarkerHeaderSize; 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci if (0 == totalBytes) { 137cb93a386Sopenharmony_ci // No non-empty ICC profile markers were found. 138cb93a386Sopenharmony_ci return nullptr; 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci // Combine the ICC marker data into a contiguous profile. 142cb93a386Sopenharmony_ci sk_sp<SkData> iccData = SkData::MakeUninitialized(totalBytes); 143cb93a386Sopenharmony_ci void* dst = iccData->writable_data(); 144cb93a386Sopenharmony_ci for (uint32_t i = 1; i <= numMarkers; i++) { 145cb93a386Sopenharmony_ci jpeg_marker_struct* marker = markerSequence[i]; 146cb93a386Sopenharmony_ci if (!marker) { 147cb93a386Sopenharmony_ci SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, numMarkers); 148cb93a386Sopenharmony_ci return nullptr; 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci void* src = SkTAddOffset<void>(marker->data, kICCMarkerHeaderSize); 152cb93a386Sopenharmony_ci size_t bytes = marker->data_length - kICCMarkerHeaderSize; 153cb93a386Sopenharmony_ci memcpy(dst, src, bytes); 154cb93a386Sopenharmony_ci dst = SkTAddOffset<void>(dst, bytes); 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci return SkEncodedInfo::ICCProfile::Make(std::move(iccData)); 158cb93a386Sopenharmony_ci} 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ciSkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, 161cb93a386Sopenharmony_ci JpegDecoderMgr** decoderMgrOut, 162cb93a386Sopenharmony_ci std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) { 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci // Create a JpegDecoderMgr to own all of the decompress information 165cb93a386Sopenharmony_ci std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci // libjpeg errors will be caught and reported here 168cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(decoderMgr->errorMgr()); 169cb93a386Sopenharmony_ci if (setjmp(jmp)) { 170cb93a386Sopenharmony_ci return decoderMgr->returnFailure("ReadHeader", kInvalidInput); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci // Initialize the decompress info and the source manager 174cb93a386Sopenharmony_ci decoderMgr->init(); 175cb93a386Sopenharmony_ci auto* dinfo = decoderMgr->dinfo(); 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci // Instruct jpeg library to save the markers that we care about. Since 178cb93a386Sopenharmony_ci // the orientation and color profile will not change, we can skip this 179cb93a386Sopenharmony_ci // step on rewinds. 180cb93a386Sopenharmony_ci if (codecOut) { 181cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kExifMarker, 0xFFFF); 182cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kICCMarker, 0xFFFF); 183cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, JPEG_APP0, 0xFFFF); 184cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp3Marker, 0xFFFF); 185cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp4Marker, 0xFFFF); 186cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp5Marker, 0xFFFF); 187cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp6Marker, 0xFFFF); 188cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp7Marker, 0xFFFF); 189cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp8Marker, 0xFFFF); 190cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp9Marker, 0xFFFF); 191cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp10Marker, 0xFFFF); 192cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp11Marker, 0xFFFF); 193cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp12Marker, 0xFFFF); 194cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp13Marker, 0xFFFF); 195cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp14Marker, 0xFFFF); 196cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kApp15Marker, 0xFFFF); 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci // Read the jpeg header 200cb93a386Sopenharmony_ci switch (jpeg_read_header(dinfo, true)) { 201cb93a386Sopenharmony_ci case JPEG_HEADER_OK: 202cb93a386Sopenharmony_ci break; 203cb93a386Sopenharmony_ci case JPEG_SUSPENDED: 204cb93a386Sopenharmony_ci return decoderMgr->returnFailure("ReadHeader", kIncompleteInput); 205cb93a386Sopenharmony_ci default: 206cb93a386Sopenharmony_ci return decoderMgr->returnFailure("ReadHeader", kInvalidInput); 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci if (codecOut) { 210cb93a386Sopenharmony_ci // Get the encoded color type 211cb93a386Sopenharmony_ci SkEncodedInfo::Color color; 212cb93a386Sopenharmony_ci if (!decoderMgr->getEncodedColor(&color)) { 213cb93a386Sopenharmony_ci return kInvalidInput; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci SkEncodedOrigin orientation = get_exif_orientation(dinfo); 217cb93a386Sopenharmony_ci auto profile = read_color_profile(dinfo); 218cb93a386Sopenharmony_ci if (profile) { 219cb93a386Sopenharmony_ci auto type = profile->profile()->data_color_space; 220cb93a386Sopenharmony_ci switch (decoderMgr->dinfo()->jpeg_color_space) { 221cb93a386Sopenharmony_ci case JCS_CMYK: 222cb93a386Sopenharmony_ci case JCS_YCCK: 223cb93a386Sopenharmony_ci if (type != skcms_Signature_CMYK) { 224cb93a386Sopenharmony_ci profile = nullptr; 225cb93a386Sopenharmony_ci } 226cb93a386Sopenharmony_ci break; 227cb93a386Sopenharmony_ci case JCS_GRAYSCALE: 228cb93a386Sopenharmony_ci if (type != skcms_Signature_Gray && 229cb93a386Sopenharmony_ci type != skcms_Signature_RGB) 230cb93a386Sopenharmony_ci { 231cb93a386Sopenharmony_ci profile = nullptr; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci break; 234cb93a386Sopenharmony_ci default: 235cb93a386Sopenharmony_ci if (type != skcms_Signature_RGB) { 236cb93a386Sopenharmony_ci profile = nullptr; 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci break; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci if (!profile) { 242cb93a386Sopenharmony_ci profile = std::move(defaultColorProfile); 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci SkEncodedInfo info = SkEncodedInfo::Make(dinfo->image_width, dinfo->image_height, 246cb93a386Sopenharmony_ci color, SkEncodedInfo::kOpaque_Alpha, 8, 247cb93a386Sopenharmony_ci std::move(profile)); 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci SkJpegCodec* codec = new SkJpegCodec(std::move(info), std::unique_ptr<SkStream>(stream), 250cb93a386Sopenharmony_ci decoderMgr.release(), orientation); 251cb93a386Sopenharmony_ci *codecOut = codec; 252cb93a386Sopenharmony_ci } else { 253cb93a386Sopenharmony_ci SkASSERT(nullptr != decoderMgrOut); 254cb93a386Sopenharmony_ci *decoderMgrOut = decoderMgr.release(); 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci return kSuccess; 257cb93a386Sopenharmony_ci} 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream, 260cb93a386Sopenharmony_ci Result* result) { 261cb93a386Sopenharmony_ci return SkJpegCodec::MakeFromStream(std::move(stream), result, nullptr); 262cb93a386Sopenharmony_ci} 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream, 265cb93a386Sopenharmony_ci Result* result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) { 266cb93a386Sopenharmony_ci SkCodec* codec = nullptr; 267cb93a386Sopenharmony_ci *result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorProfile)); 268cb93a386Sopenharmony_ci if (kSuccess == *result) { 269cb93a386Sopenharmony_ci // Codec has taken ownership of the stream, we do not need to delete it 270cb93a386Sopenharmony_ci SkASSERT(codec); 271cb93a386Sopenharmony_ci stream.release(); 272cb93a386Sopenharmony_ci return std::unique_ptr<SkCodec>(codec); 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci return nullptr; 275cb93a386Sopenharmony_ci} 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ciSkJpegCodec::SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, 278cb93a386Sopenharmony_ci JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin) 279cb93a386Sopenharmony_ci : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin) 280cb93a386Sopenharmony_ci , fDecoderMgr(decoderMgr) 281cb93a386Sopenharmony_ci , fReadyState(decoderMgr->dinfo()->global_state) 282cb93a386Sopenharmony_ci , fSwizzleSrcRow(nullptr) 283cb93a386Sopenharmony_ci , fColorXformSrcRow(nullptr) 284cb93a386Sopenharmony_ci , fSwizzlerSubset(SkIRect::MakeEmpty()) 285cb93a386Sopenharmony_ci{} 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci/* 288cb93a386Sopenharmony_ci * Return the row bytes of a particular image type and width 289cb93a386Sopenharmony_ci */ 290cb93a386Sopenharmony_cistatic size_t get_row_bytes(const j_decompress_ptr dinfo) { 291cb93a386Sopenharmony_ci const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : 292cb93a386Sopenharmony_ci dinfo->out_color_components; 293cb93a386Sopenharmony_ci return dinfo->output_width * colorBytes; 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci} 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci/* 298cb93a386Sopenharmony_ci * Calculate output dimensions based on the provided factors. 299cb93a386Sopenharmony_ci * 300cb93a386Sopenharmony_ci * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will 301cb93a386Sopenharmony_ci * incorrectly modify num_components. 302cb93a386Sopenharmony_ci */ 303cb93a386Sopenharmony_civoid calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) { 304cb93a386Sopenharmony_ci dinfo->num_components = 0; 305cb93a386Sopenharmony_ci dinfo->scale_num = num; 306cb93a386Sopenharmony_ci dinfo->scale_denom = denom; 307cb93a386Sopenharmony_ci jpeg_calc_output_dimensions(dinfo); 308cb93a386Sopenharmony_ci} 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ci/* 311cb93a386Sopenharmony_ci * Return a valid set of output dimensions for this decoder, given an input scale 312cb93a386Sopenharmony_ci */ 313cb93a386Sopenharmony_ciSkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { 314cb93a386Sopenharmony_ci // libjpeg-turbo supports scaling by 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1, so we will 315cb93a386Sopenharmony_ci // support these as well 316cb93a386Sopenharmony_ci unsigned int num; 317cb93a386Sopenharmony_ci unsigned int denom = 8; 318cb93a386Sopenharmony_ci if (desiredScale >= 0.9375) { 319cb93a386Sopenharmony_ci num = 8; 320cb93a386Sopenharmony_ci } else if (desiredScale >= 0.8125) { 321cb93a386Sopenharmony_ci num = 7; 322cb93a386Sopenharmony_ci } else if (desiredScale >= 0.6875f) { 323cb93a386Sopenharmony_ci num = 6; 324cb93a386Sopenharmony_ci } else if (desiredScale >= 0.5625f) { 325cb93a386Sopenharmony_ci num = 5; 326cb93a386Sopenharmony_ci } else if (desiredScale >= 0.4375f) { 327cb93a386Sopenharmony_ci num = 4; 328cb93a386Sopenharmony_ci } else if (desiredScale >= 0.3125f) { 329cb93a386Sopenharmony_ci num = 3; 330cb93a386Sopenharmony_ci } else if (desiredScale >= 0.1875f) { 331cb93a386Sopenharmony_ci num = 2; 332cb93a386Sopenharmony_ci } else { 333cb93a386Sopenharmony_ci num = 1; 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions 337cb93a386Sopenharmony_ci jpeg_decompress_struct dinfo; 338cb93a386Sopenharmony_ci sk_bzero(&dinfo, sizeof(dinfo)); 339cb93a386Sopenharmony_ci dinfo.image_width = this->dimensions().width(); 340cb93a386Sopenharmony_ci dinfo.image_height = this->dimensions().height(); 341cb93a386Sopenharmony_ci dinfo.global_state = fReadyState; 342cb93a386Sopenharmony_ci calc_output_dimensions(&dinfo, num, denom); 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci // Return the calculated output dimensions for the given scale 345cb93a386Sopenharmony_ci return SkISize::Make(dinfo.output_width, dinfo.output_height); 346cb93a386Sopenharmony_ci} 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_cibool SkJpegCodec::onRewind() { 349cb93a386Sopenharmony_ci JpegDecoderMgr* decoderMgr = nullptr; 350cb93a386Sopenharmony_ci if (kSuccess != ReadHeader(this->stream(), nullptr, &decoderMgr, nullptr)) { 351cb93a386Sopenharmony_ci return fDecoderMgr->returnFalse("onRewind"); 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci SkASSERT(nullptr != decoderMgr); 354cb93a386Sopenharmony_ci fDecoderMgr.reset(decoderMgr); 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci fSwizzler.reset(nullptr); 357cb93a386Sopenharmony_ci fSwizzleSrcRow = nullptr; 358cb93a386Sopenharmony_ci fColorXformSrcRow = nullptr; 359cb93a386Sopenharmony_ci fStorage.reset(); 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci return true; 362cb93a386Sopenharmony_ci} 363cb93a386Sopenharmony_ci 364cb93a386Sopenharmony_cibool SkJpegCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque, 365cb93a386Sopenharmony_ci bool needsColorXform) { 366cb93a386Sopenharmony_ci SkASSERT(srcIsOpaque); 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci if (kUnknown_SkAlphaType == dstInfo.alphaType()) { 369cb93a386Sopenharmony_ci return false; 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci if (kOpaque_SkAlphaType != dstInfo.alphaType()) { 373cb93a386Sopenharmony_ci SkCodecPrintf("Warning: an opaque image should be decoded as opaque " 374cb93a386Sopenharmony_ci "- it is being decoded as non-opaque, which will draw slower\n"); 375cb93a386Sopenharmony_ci } 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space; 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci // Check for valid color types and set the output color space 380cb93a386Sopenharmony_ci switch (dstInfo.colorType()) { 381cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 382cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 383cb93a386Sopenharmony_ci break; 384cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 385cb93a386Sopenharmony_ci if (needsColorXform) { 386cb93a386Sopenharmony_ci // Always using RGBA as the input format for color xforms makes the 387cb93a386Sopenharmony_ci // implementation a little simpler. 388cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 389cb93a386Sopenharmony_ci } else { 390cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; 391cb93a386Sopenharmony_ci } 392cb93a386Sopenharmony_ci break; 393cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 394cb93a386Sopenharmony_ci if (needsColorXform) { 395cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 396cb93a386Sopenharmony_ci } else { 397cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; 398cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci break; 401cb93a386Sopenharmony_ci case kGray_8_SkColorType: 402cb93a386Sopenharmony_ci if (JCS_GRAYSCALE != encodedColorType) { 403cb93a386Sopenharmony_ci return false; 404cb93a386Sopenharmony_ci } 405cb93a386Sopenharmony_ci 406cb93a386Sopenharmony_ci if (needsColorXform) { 407cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 408cb93a386Sopenharmony_ci } else { 409cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; 410cb93a386Sopenharmony_ci } 411cb93a386Sopenharmony_ci break; 412cb93a386Sopenharmony_ci case kRGBA_F16_SkColorType: 413cb93a386Sopenharmony_ci SkASSERT(needsColorXform); 414cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 415cb93a386Sopenharmony_ci break; 416cb93a386Sopenharmony_ci default: 417cb93a386Sopenharmony_ci return false; 418cb93a386Sopenharmony_ci } 419cb93a386Sopenharmony_ci 420cb93a386Sopenharmony_ci // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so 421cb93a386Sopenharmony_ci // we must do it ourselves. 422cb93a386Sopenharmony_ci if (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType) { 423cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_ci return true; 427cb93a386Sopenharmony_ci} 428cb93a386Sopenharmony_ci 429cb93a386Sopenharmony_ci/* 430cb93a386Sopenharmony_ci * Checks if we can natively scale to the requested dimensions and natively scales the 431cb93a386Sopenharmony_ci * dimensions if possible 432cb93a386Sopenharmony_ci */ 433cb93a386Sopenharmony_cibool SkJpegCodec::onDimensionsSupported(const SkISize& size) { 434cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr()); 435cb93a386Sopenharmony_ci if (setjmp(jmp)) { 436cb93a386Sopenharmony_ci return fDecoderMgr->returnFalse("onDimensionsSupported"); 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci const unsigned int dstWidth = size.width(); 440cb93a386Sopenharmony_ci const unsigned int dstHeight = size.height(); 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions 443cb93a386Sopenharmony_ci // FIXME: Why is this necessary? 444cb93a386Sopenharmony_ci jpeg_decompress_struct dinfo; 445cb93a386Sopenharmony_ci sk_bzero(&dinfo, sizeof(dinfo)); 446cb93a386Sopenharmony_ci dinfo.image_width = this->dimensions().width(); 447cb93a386Sopenharmony_ci dinfo.image_height = this->dimensions().height(); 448cb93a386Sopenharmony_ci dinfo.global_state = fReadyState; 449cb93a386Sopenharmony_ci 450cb93a386Sopenharmony_ci // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1 451cb93a386Sopenharmony_ci unsigned int num = 8; 452cb93a386Sopenharmony_ci const unsigned int denom = 8; 453cb93a386Sopenharmony_ci calc_output_dimensions(&dinfo, num, denom); 454cb93a386Sopenharmony_ci while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) { 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci // Return a failure if we have tried all of the possible scales 457cb93a386Sopenharmony_ci if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) { 458cb93a386Sopenharmony_ci return false; 459cb93a386Sopenharmony_ci } 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci // Try the next scale 462cb93a386Sopenharmony_ci num -= 1; 463cb93a386Sopenharmony_ci calc_output_dimensions(&dinfo, num, denom); 464cb93a386Sopenharmony_ci } 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->scale_num = num; 467cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->scale_denom = denom; 468cb93a386Sopenharmony_ci return true; 469cb93a386Sopenharmony_ci} 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ciint SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, 472cb93a386Sopenharmony_ci const Options& opts) { 473cb93a386Sopenharmony_ci // Set the jump location for libjpeg-turbo errors 474cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr()); 475cb93a386Sopenharmony_ci if (setjmp(jmp)) { 476cb93a386Sopenharmony_ci return 0; 477cb93a386Sopenharmony_ci } 478cb93a386Sopenharmony_ci 479cb93a386Sopenharmony_ci // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case, 480cb93a386Sopenharmony_ci // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer. 481cb93a386Sopenharmony_ci // We can never swizzle "in place" because the swizzler may perform sampling and/or 482cb93a386Sopenharmony_ci // subsetting. 483cb93a386Sopenharmony_ci // When fColorXformSrcRow is non-null, it means that we need to color xform and that 484cb93a386Sopenharmony_ci // we cannot color xform "in place" (many times we can, but not when the src and dst 485cb93a386Sopenharmony_ci // are different sizes). 486cb93a386Sopenharmony_ci // In this case, we will color xform from fColorXformSrcRow into the dst. 487cb93a386Sopenharmony_ci JSAMPLE* decodeDst = (JSAMPLE*) dst; 488cb93a386Sopenharmony_ci uint32_t* swizzleDst = (uint32_t*) dst; 489cb93a386Sopenharmony_ci size_t decodeDstRowBytes = rowBytes; 490cb93a386Sopenharmony_ci size_t swizzleDstRowBytes = rowBytes; 491cb93a386Sopenharmony_ci int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width(); 492cb93a386Sopenharmony_ci if (fSwizzleSrcRow && fColorXformSrcRow) { 493cb93a386Sopenharmony_ci decodeDst = (JSAMPLE*) fSwizzleSrcRow; 494cb93a386Sopenharmony_ci swizzleDst = fColorXformSrcRow; 495cb93a386Sopenharmony_ci decodeDstRowBytes = 0; 496cb93a386Sopenharmony_ci swizzleDstRowBytes = 0; 497cb93a386Sopenharmony_ci dstWidth = fSwizzler->swizzleWidth(); 498cb93a386Sopenharmony_ci } else if (fColorXformSrcRow) { 499cb93a386Sopenharmony_ci decodeDst = (JSAMPLE*) fColorXformSrcRow; 500cb93a386Sopenharmony_ci swizzleDst = fColorXformSrcRow; 501cb93a386Sopenharmony_ci decodeDstRowBytes = 0; 502cb93a386Sopenharmony_ci swizzleDstRowBytes = 0; 503cb93a386Sopenharmony_ci } else if (fSwizzleSrcRow) { 504cb93a386Sopenharmony_ci decodeDst = (JSAMPLE*) fSwizzleSrcRow; 505cb93a386Sopenharmony_ci decodeDstRowBytes = 0; 506cb93a386Sopenharmony_ci dstWidth = fSwizzler->swizzleWidth(); 507cb93a386Sopenharmony_ci } 508cb93a386Sopenharmony_ci 509cb93a386Sopenharmony_ci for (int y = 0; y < count; y++) { 510cb93a386Sopenharmony_ci uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1); 511cb93a386Sopenharmony_ci if (0 == lines) { 512cb93a386Sopenharmony_ci return y; 513cb93a386Sopenharmony_ci } 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ci if (fSwizzler) { 516cb93a386Sopenharmony_ci fSwizzler->swizzle(swizzleDst, decodeDst); 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci if (this->colorXform()) { 520cb93a386Sopenharmony_ci this->applyColorXform(dst, swizzleDst, dstWidth); 521cb93a386Sopenharmony_ci dst = SkTAddOffset<void>(dst, rowBytes); 522cb93a386Sopenharmony_ci } 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ci decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes); 525cb93a386Sopenharmony_ci swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes); 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci return count; 529cb93a386Sopenharmony_ci} 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ci/* 532cb93a386Sopenharmony_ci * This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is 533cb93a386Sopenharmony_ci * encoded as CMYK. 534cb93a386Sopenharmony_ci * And even then we still may not need it. If the jpeg has a CMYK color profile and a color 535cb93a386Sopenharmony_ci * xform, the color xform will handle the CMYK->RGB conversion. 536cb93a386Sopenharmony_ci */ 537cb93a386Sopenharmony_cistatic inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType, 538cb93a386Sopenharmony_ci const skcms_ICCProfile* srcProfile, 539cb93a386Sopenharmony_ci bool hasColorSpaceXform) { 540cb93a386Sopenharmony_ci if (JCS_CMYK != jpegColorType) { 541cb93a386Sopenharmony_ci return false; 542cb93a386Sopenharmony_ci } 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci bool hasCMYKColorSpace = srcProfile && srcProfile->data_color_space == skcms_Signature_CMYK; 545cb93a386Sopenharmony_ci return !hasCMYKColorSpace || !hasColorSpaceXform; 546cb93a386Sopenharmony_ci} 547cb93a386Sopenharmony_ci 548cb93a386Sopenharmony_ci/* 549cb93a386Sopenharmony_ci * Performs the jpeg decode 550cb93a386Sopenharmony_ci */ 551cb93a386Sopenharmony_ciSkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, 552cb93a386Sopenharmony_ci void* dst, size_t dstRowBytes, 553cb93a386Sopenharmony_ci const Options& options, 554cb93a386Sopenharmony_ci int* rowsDecoded) { 555cb93a386Sopenharmony_ci if (options.fSubset) { 556cb93a386Sopenharmony_ci // Subsets are not supported. 557cb93a386Sopenharmony_ci return kUnimplemented; 558cb93a386Sopenharmony_ci } 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci // Get a pointer to the decompress info since we will use it quite frequently 561cb93a386Sopenharmony_ci jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); 562cb93a386Sopenharmony_ci 563cb93a386Sopenharmony_ci // Set the jump location for libjpeg errors 564cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr()); 565cb93a386Sopenharmony_ci if (setjmp(jmp)) { 566cb93a386Sopenharmony_ci return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci if (!jpeg_start_decompress(dinfo)) { 570cb93a386Sopenharmony_ci return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 571cb93a386Sopenharmony_ci } 572cb93a386Sopenharmony_ci 573cb93a386Sopenharmony_ci // The recommended output buffer height should always be 1 in high quality modes. 574cb93a386Sopenharmony_ci // If it's not, we want to know because it means our strategy is not optimal. 575cb93a386Sopenharmony_ci SkASSERT(1 == dinfo->rec_outbuf_height); 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_ci if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space, 578cb93a386Sopenharmony_ci this->getEncodedInfo().profile(), this->colorXform())) { 579cb93a386Sopenharmony_ci this->initializeSwizzler(dstInfo, options, true); 580cb93a386Sopenharmony_ci } 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci if (!this->allocateStorage(dstInfo)) { 583cb93a386Sopenharmony_ci return kInternalError; 584cb93a386Sopenharmony_ci } 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options); 587cb93a386Sopenharmony_ci if (rows < dstInfo.height()) { 588cb93a386Sopenharmony_ci *rowsDecoded = rows; 589cb93a386Sopenharmony_ci return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput); 590cb93a386Sopenharmony_ci } 591cb93a386Sopenharmony_ci 592cb93a386Sopenharmony_ci return kSuccess; 593cb93a386Sopenharmony_ci} 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_cibool SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) { 596cb93a386Sopenharmony_ci int dstWidth = dstInfo.width(); 597cb93a386Sopenharmony_ci 598cb93a386Sopenharmony_ci size_t swizzleBytes = 0; 599cb93a386Sopenharmony_ci if (fSwizzler) { 600cb93a386Sopenharmony_ci swizzleBytes = get_row_bytes(fDecoderMgr->dinfo()); 601cb93a386Sopenharmony_ci dstWidth = fSwizzler->swizzleWidth(); 602cb93a386Sopenharmony_ci SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes)); 603cb93a386Sopenharmony_ci } 604cb93a386Sopenharmony_ci 605cb93a386Sopenharmony_ci size_t xformBytes = 0; 606cb93a386Sopenharmony_ci 607cb93a386Sopenharmony_ci if (this->colorXform() && sizeof(uint32_t) != dstInfo.bytesPerPixel()) { 608cb93a386Sopenharmony_ci xformBytes = dstWidth * sizeof(uint32_t); 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_ci size_t totalBytes = swizzleBytes + xformBytes; 612cb93a386Sopenharmony_ci if (totalBytes > 0) { 613cb93a386Sopenharmony_ci if (!fStorage.reset(totalBytes)) { 614cb93a386Sopenharmony_ci return false; 615cb93a386Sopenharmony_ci } 616cb93a386Sopenharmony_ci fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr; 617cb93a386Sopenharmony_ci fColorXformSrcRow = (xformBytes > 0) ? 618cb93a386Sopenharmony_ci SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr; 619cb93a386Sopenharmony_ci } 620cb93a386Sopenharmony_ci return true; 621cb93a386Sopenharmony_ci} 622cb93a386Sopenharmony_ci 623cb93a386Sopenharmony_civoid SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options, 624cb93a386Sopenharmony_ci bool needsCMYKToRGB) { 625cb93a386Sopenharmony_ci Options swizzlerOptions = options; 626cb93a386Sopenharmony_ci if (options.fSubset) { 627cb93a386Sopenharmony_ci // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case 628cb93a386Sopenharmony_ci // where libjpeg-turbo provides a subset and then we need to subset it further. 629cb93a386Sopenharmony_ci // Also, verify that fSwizzlerSubset is initialized and valid. 630cb93a386Sopenharmony_ci SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() && 631cb93a386Sopenharmony_ci fSwizzlerSubset.width() == options.fSubset->width()); 632cb93a386Sopenharmony_ci swizzlerOptions.fSubset = &fSwizzlerSubset; 633cb93a386Sopenharmony_ci } 634cb93a386Sopenharmony_ci 635cb93a386Sopenharmony_ci SkImageInfo swizzlerDstInfo = dstInfo; 636cb93a386Sopenharmony_ci if (this->colorXform()) { 637cb93a386Sopenharmony_ci // The color xform will be expecting RGBA 8888 input. 638cb93a386Sopenharmony_ci swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType); 639cb93a386Sopenharmony_ci } 640cb93a386Sopenharmony_ci 641cb93a386Sopenharmony_ci if (needsCMYKToRGB) { 642cb93a386Sopenharmony_ci // The swizzler is used to convert to from CMYK. 643cb93a386Sopenharmony_ci // The swizzler does not use the width or height on SkEncodedInfo. 644cb93a386Sopenharmony_ci auto swizzlerInfo = SkEncodedInfo::Make(0, 0, SkEncodedInfo::kInvertedCMYK_Color, 645cb93a386Sopenharmony_ci SkEncodedInfo::kOpaque_Alpha, 8); 646cb93a386Sopenharmony_ci fSwizzler = SkSwizzler::Make(swizzlerInfo, nullptr, swizzlerDstInfo, swizzlerOptions); 647cb93a386Sopenharmony_ci } else { 648cb93a386Sopenharmony_ci int srcBPP = 0; 649cb93a386Sopenharmony_ci switch (fDecoderMgr->dinfo()->out_color_space) { 650cb93a386Sopenharmony_ci case JCS_EXT_RGBA: 651cb93a386Sopenharmony_ci case JCS_EXT_BGRA: 652cb93a386Sopenharmony_ci case JCS_CMYK: 653cb93a386Sopenharmony_ci srcBPP = 4; 654cb93a386Sopenharmony_ci break; 655cb93a386Sopenharmony_ci case JCS_RGB565: 656cb93a386Sopenharmony_ci srcBPP = 2; 657cb93a386Sopenharmony_ci break; 658cb93a386Sopenharmony_ci case JCS_GRAYSCALE: 659cb93a386Sopenharmony_ci srcBPP = 1; 660cb93a386Sopenharmony_ci break; 661cb93a386Sopenharmony_ci default: 662cb93a386Sopenharmony_ci SkASSERT(false); 663cb93a386Sopenharmony_ci break; 664cb93a386Sopenharmony_ci } 665cb93a386Sopenharmony_ci fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerDstInfo, swizzlerOptions); 666cb93a386Sopenharmony_ci } 667cb93a386Sopenharmony_ci SkASSERT(fSwizzler); 668cb93a386Sopenharmony_ci} 669cb93a386Sopenharmony_ci 670cb93a386Sopenharmony_ciSkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { 671cb93a386Sopenharmony_ci if (!createIfNecessary || fSwizzler) { 672cb93a386Sopenharmony_ci SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow)); 673cb93a386Sopenharmony_ci return fSwizzler.get(); 674cb93a386Sopenharmony_ci } 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_ci bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk( 677cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(), 678cb93a386Sopenharmony_ci this->colorXform()); 679cb93a386Sopenharmony_ci this->initializeSwizzler(this->dstInfo(), this->options(), needsCMYKToRGB); 680cb93a386Sopenharmony_ci if (!this->allocateStorage(this->dstInfo())) { 681cb93a386Sopenharmony_ci return nullptr; 682cb93a386Sopenharmony_ci } 683cb93a386Sopenharmony_ci return fSwizzler.get(); 684cb93a386Sopenharmony_ci} 685cb93a386Sopenharmony_ci 686cb93a386Sopenharmony_ciSkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, 687cb93a386Sopenharmony_ci const Options& options) { 688cb93a386Sopenharmony_ci // Set the jump location for libjpeg errors 689cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr()); 690cb93a386Sopenharmony_ci if (setjmp(jmp)) { 691cb93a386Sopenharmony_ci SkCodecPrintf("setjmp: Error from libjpeg\n"); 692cb93a386Sopenharmony_ci return kInvalidInput; 693cb93a386Sopenharmony_ci } 694cb93a386Sopenharmony_ci 695cb93a386Sopenharmony_ci if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { 696cb93a386Sopenharmony_ci SkCodecPrintf("start decompress failed\n"); 697cb93a386Sopenharmony_ci return kInvalidInput; 698cb93a386Sopenharmony_ci } 699cb93a386Sopenharmony_ci 700cb93a386Sopenharmony_ci bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk( 701cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(), 702cb93a386Sopenharmony_ci this->colorXform()); 703cb93a386Sopenharmony_ci if (options.fSubset) { 704cb93a386Sopenharmony_ci uint32_t startX = options.fSubset->x(); 705cb93a386Sopenharmony_ci uint32_t width = options.fSubset->width(); 706cb93a386Sopenharmony_ci 707cb93a386Sopenharmony_ci // libjpeg-turbo may need to align startX to a multiple of the IDCT 708cb93a386Sopenharmony_ci // block size. If this is the case, it will decrease the value of 709cb93a386Sopenharmony_ci // startX to the appropriate alignment and also increase the value 710cb93a386Sopenharmony_ci // of width so that the right edge of the requested subset remains 711cb93a386Sopenharmony_ci // the same. 712cb93a386Sopenharmony_ci jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width); 713cb93a386Sopenharmony_ci 714cb93a386Sopenharmony_ci SkASSERT(startX <= (uint32_t) options.fSubset->x()); 715cb93a386Sopenharmony_ci SkASSERT(width >= (uint32_t) options.fSubset->width()); 716cb93a386Sopenharmony_ci SkASSERT(startX + width >= (uint32_t) options.fSubset->right()); 717cb93a386Sopenharmony_ci 718cb93a386Sopenharmony_ci // Instruct the swizzler (if it is necessary) to further subset the 719cb93a386Sopenharmony_ci // output provided by libjpeg-turbo. 720cb93a386Sopenharmony_ci // 721cb93a386Sopenharmony_ci // We set this here (rather than in the if statement below), so that 722cb93a386Sopenharmony_ci // if (1) we don't need a swizzler for the subset, and (2) we need a 723cb93a386Sopenharmony_ci // swizzler for CMYK, the swizzler will still use the proper subset 724cb93a386Sopenharmony_ci // dimensions. 725cb93a386Sopenharmony_ci // 726cb93a386Sopenharmony_ci // Note that the swizzler will ignore the y and height parameters of 727cb93a386Sopenharmony_ci // the subset. Since the scanline decoder (and the swizzler) handle 728cb93a386Sopenharmony_ci // one row at a time, only the subsetting in the x-dimension matters. 729cb93a386Sopenharmony_ci fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0, 730cb93a386Sopenharmony_ci options.fSubset->width(), options.fSubset->height()); 731cb93a386Sopenharmony_ci 732cb93a386Sopenharmony_ci // We will need a swizzler if libjpeg-turbo cannot provide the exact 733cb93a386Sopenharmony_ci // subset that we request. 734cb93a386Sopenharmony_ci if (startX != (uint32_t) options.fSubset->x() || 735cb93a386Sopenharmony_ci width != (uint32_t) options.fSubset->width()) { 736cb93a386Sopenharmony_ci this->initializeSwizzler(dstInfo, options, needsCMYKToRGB); 737cb93a386Sopenharmony_ci } 738cb93a386Sopenharmony_ci } 739cb93a386Sopenharmony_ci 740cb93a386Sopenharmony_ci // Make sure we have a swizzler if we are converting from CMYK. 741cb93a386Sopenharmony_ci if (!fSwizzler && needsCMYKToRGB) { 742cb93a386Sopenharmony_ci this->initializeSwizzler(dstInfo, options, true); 743cb93a386Sopenharmony_ci } 744cb93a386Sopenharmony_ci 745cb93a386Sopenharmony_ci if (!this->allocateStorage(dstInfo)) { 746cb93a386Sopenharmony_ci return kInternalError; 747cb93a386Sopenharmony_ci } 748cb93a386Sopenharmony_ci 749cb93a386Sopenharmony_ci return kSuccess; 750cb93a386Sopenharmony_ci} 751cb93a386Sopenharmony_ci 752cb93a386Sopenharmony_ciint SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { 753cb93a386Sopenharmony_ci int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options()); 754cb93a386Sopenharmony_ci if (rows < count) { 755cb93a386Sopenharmony_ci // This allows us to skip calling jpeg_finish_decompress(). 756cb93a386Sopenharmony_ci fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci 759cb93a386Sopenharmony_ci return rows; 760cb93a386Sopenharmony_ci} 761cb93a386Sopenharmony_ci 762cb93a386Sopenharmony_cibool SkJpegCodec::onSkipScanlines(int count) { 763cb93a386Sopenharmony_ci // Set the jump location for libjpeg errors 764cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr()); 765cb93a386Sopenharmony_ci if (setjmp(jmp)) { 766cb93a386Sopenharmony_ci return fDecoderMgr->returnFalse("onSkipScanlines"); 767cb93a386Sopenharmony_ci } 768cb93a386Sopenharmony_ci 769cb93a386Sopenharmony_ci return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); 770cb93a386Sopenharmony_ci} 771cb93a386Sopenharmony_ci 772cb93a386Sopenharmony_cistatic bool is_yuv_supported(const jpeg_decompress_struct* dinfo, 773cb93a386Sopenharmony_ci const SkJpegCodec& codec, 774cb93a386Sopenharmony_ci const SkYUVAPixmapInfo::SupportedDataTypes* supportedDataTypes, 775cb93a386Sopenharmony_ci SkYUVAPixmapInfo* yuvaPixmapInfo) { 776cb93a386Sopenharmony_ci // Scaling is not supported in raw data mode. 777cb93a386Sopenharmony_ci SkASSERT(dinfo->scale_num == dinfo->scale_denom); 778cb93a386Sopenharmony_ci 779cb93a386Sopenharmony_ci // I can't imagine that this would ever change, but we do depend on it. 780cb93a386Sopenharmony_ci static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8."); 781cb93a386Sopenharmony_ci 782cb93a386Sopenharmony_ci if (JCS_YCbCr != dinfo->jpeg_color_space) { 783cb93a386Sopenharmony_ci return false; 784cb93a386Sopenharmony_ci } 785cb93a386Sopenharmony_ci 786cb93a386Sopenharmony_ci SkASSERT(3 == dinfo->num_components); 787cb93a386Sopenharmony_ci SkASSERT(dinfo->comp_info); 788cb93a386Sopenharmony_ci 789cb93a386Sopenharmony_ci // It is possible to perform a YUV decode for any combination of 790cb93a386Sopenharmony_ci // horizontal and vertical sampling that is supported by 791cb93a386Sopenharmony_ci // libjpeg/libjpeg-turbo. However, we will start by supporting only the 792cb93a386Sopenharmony_ci // common cases (where U and V have samp_factors of one). 793cb93a386Sopenharmony_ci // 794cb93a386Sopenharmony_ci // The definition of samp_factor is kind of the opposite of what SkCodec 795cb93a386Sopenharmony_ci // thinks of as a sampling factor. samp_factor is essentially a 796cb93a386Sopenharmony_ci // multiplier, and the larger the samp_factor is, the more samples that 797cb93a386Sopenharmony_ci // there will be. Ex: 798cb93a386Sopenharmony_ci // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor) 799cb93a386Sopenharmony_ci // 800cb93a386Sopenharmony_ci // Supporting cases where the samp_factors for U or V were larger than 801cb93a386Sopenharmony_ci // that of Y would be an extremely difficult change, given that clients 802cb93a386Sopenharmony_ci // allocate memory as if the size of the Y plane is always the size of the 803cb93a386Sopenharmony_ci // image. However, this case is very, very rare. 804cb93a386Sopenharmony_ci if ((1 != dinfo->comp_info[1].h_samp_factor) || 805cb93a386Sopenharmony_ci (1 != dinfo->comp_info[1].v_samp_factor) || 806cb93a386Sopenharmony_ci (1 != dinfo->comp_info[2].h_samp_factor) || 807cb93a386Sopenharmony_ci (1 != dinfo->comp_info[2].v_samp_factor)) 808cb93a386Sopenharmony_ci { 809cb93a386Sopenharmony_ci return false; 810cb93a386Sopenharmony_ci } 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_ci // Support all common cases of Y samp_factors. 813cb93a386Sopenharmony_ci // TODO (msarett): As mentioned above, it would be possible to support 814cb93a386Sopenharmony_ci // more combinations of samp_factors. The issues are: 815cb93a386Sopenharmony_ci // (1) Are there actually any images that are not covered 816cb93a386Sopenharmony_ci // by these cases? 817cb93a386Sopenharmony_ci // (2) How much complexity would be added to the 818cb93a386Sopenharmony_ci // implementation in order to support these rare 819cb93a386Sopenharmony_ci // cases? 820cb93a386Sopenharmony_ci int hSampY = dinfo->comp_info[0].h_samp_factor; 821cb93a386Sopenharmony_ci int vSampY = dinfo->comp_info[0].v_samp_factor; 822cb93a386Sopenharmony_ci SkASSERT(hSampY == dinfo->max_h_samp_factor); 823cb93a386Sopenharmony_ci SkASSERT(vSampY == dinfo->max_v_samp_factor); 824cb93a386Sopenharmony_ci 825cb93a386Sopenharmony_ci SkYUVAInfo::Subsampling tempSubsampling; 826cb93a386Sopenharmony_ci if (1 == hSampY && 1 == vSampY) { 827cb93a386Sopenharmony_ci tempSubsampling = SkYUVAInfo::Subsampling::k444; 828cb93a386Sopenharmony_ci } else if (2 == hSampY && 1 == vSampY) { 829cb93a386Sopenharmony_ci tempSubsampling = SkYUVAInfo::Subsampling::k422; 830cb93a386Sopenharmony_ci } else if (2 == hSampY && 2 == vSampY) { 831cb93a386Sopenharmony_ci tempSubsampling = SkYUVAInfo::Subsampling::k420; 832cb93a386Sopenharmony_ci } else if (1 == hSampY && 2 == vSampY) { 833cb93a386Sopenharmony_ci tempSubsampling = SkYUVAInfo::Subsampling::k440; 834cb93a386Sopenharmony_ci } else if (4 == hSampY && 1 == vSampY) { 835cb93a386Sopenharmony_ci tempSubsampling = SkYUVAInfo::Subsampling::k411; 836cb93a386Sopenharmony_ci } else if (4 == hSampY && 2 == vSampY) { 837cb93a386Sopenharmony_ci tempSubsampling = SkYUVAInfo::Subsampling::k410; 838cb93a386Sopenharmony_ci } else { 839cb93a386Sopenharmony_ci return false; 840cb93a386Sopenharmony_ci } 841cb93a386Sopenharmony_ci if (supportedDataTypes && 842cb93a386Sopenharmony_ci !supportedDataTypes->supported(SkYUVAInfo::PlaneConfig::kY_U_V, 843cb93a386Sopenharmony_ci SkYUVAPixmapInfo::DataType::kUnorm8)) { 844cb93a386Sopenharmony_ci return false; 845cb93a386Sopenharmony_ci } 846cb93a386Sopenharmony_ci if (yuvaPixmapInfo) { 847cb93a386Sopenharmony_ci SkColorType colorTypes[SkYUVAPixmapInfo::kMaxPlanes]; 848cb93a386Sopenharmony_ci size_t rowBytes[SkYUVAPixmapInfo::kMaxPlanes]; 849cb93a386Sopenharmony_ci for (int i = 0; i < 3; ++i) { 850cb93a386Sopenharmony_ci colorTypes[i] = kAlpha_8_SkColorType; 851cb93a386Sopenharmony_ci rowBytes[i] = dinfo->comp_info[i].width_in_blocks * DCTSIZE; 852cb93a386Sopenharmony_ci } 853cb93a386Sopenharmony_ci SkYUVAInfo yuvaInfo(codec.dimensions(), 854cb93a386Sopenharmony_ci SkYUVAInfo::PlaneConfig::kY_U_V, 855cb93a386Sopenharmony_ci tempSubsampling, 856cb93a386Sopenharmony_ci kJPEG_Full_SkYUVColorSpace, 857cb93a386Sopenharmony_ci codec.getOrigin(), 858cb93a386Sopenharmony_ci SkYUVAInfo::Siting::kCentered, 859cb93a386Sopenharmony_ci SkYUVAInfo::Siting::kCentered); 860cb93a386Sopenharmony_ci *yuvaPixmapInfo = SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes); 861cb93a386Sopenharmony_ci } 862cb93a386Sopenharmony_ci return true; 863cb93a386Sopenharmony_ci} 864cb93a386Sopenharmony_ci 865cb93a386Sopenharmony_cibool SkJpegCodec::onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, 866cb93a386Sopenharmony_ci SkYUVAPixmapInfo* yuvaPixmapInfo) const { 867cb93a386Sopenharmony_ci jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); 868cb93a386Sopenharmony_ci return is_yuv_supported(dinfo, *this, &supportedDataTypes, yuvaPixmapInfo); 869cb93a386Sopenharmony_ci} 870cb93a386Sopenharmony_ci 871cb93a386Sopenharmony_ciSkCodec::Result SkJpegCodec::onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { 872cb93a386Sopenharmony_ci // Get a pointer to the decompress info since we will use it quite frequently 873cb93a386Sopenharmony_ci jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); 874cb93a386Sopenharmony_ci if (!is_yuv_supported(dinfo, *this, nullptr, nullptr)) { 875cb93a386Sopenharmony_ci return fDecoderMgr->returnFailure("onGetYUVAPlanes", kInvalidInput); 876cb93a386Sopenharmony_ci } 877cb93a386Sopenharmony_ci // Set the jump location for libjpeg errors 878cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr()); 879cb93a386Sopenharmony_ci if (setjmp(jmp)) { 880cb93a386Sopenharmony_ci return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 881cb93a386Sopenharmony_ci } 882cb93a386Sopenharmony_ci 883cb93a386Sopenharmony_ci dinfo->raw_data_out = TRUE; 884cb93a386Sopenharmony_ci if (!jpeg_start_decompress(dinfo)) { 885cb93a386Sopenharmony_ci return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 886cb93a386Sopenharmony_ci } 887cb93a386Sopenharmony_ci 888cb93a386Sopenharmony_ci const std::array<SkPixmap, SkYUVAPixmaps::kMaxPlanes>& planes = yuvaPixmaps.planes(); 889cb93a386Sopenharmony_ci 890cb93a386Sopenharmony_ci#ifdef SK_DEBUG 891cb93a386Sopenharmony_ci { 892cb93a386Sopenharmony_ci // A previous implementation claims that the return value of is_yuv_supported() 893cb93a386Sopenharmony_ci // may change after calling jpeg_start_decompress(). It looks to me like this 894cb93a386Sopenharmony_ci // was caused by a bug in the old code, but we'll be safe and check here. 895cb93a386Sopenharmony_ci // Also check that pixmap properties agree with expectations. 896cb93a386Sopenharmony_ci SkYUVAPixmapInfo info; 897cb93a386Sopenharmony_ci SkASSERT(is_yuv_supported(dinfo, *this, nullptr, &info)); 898cb93a386Sopenharmony_ci SkASSERT(info.yuvaInfo() == yuvaPixmaps.yuvaInfo()); 899cb93a386Sopenharmony_ci for (int i = 0; i < info.numPlanes(); ++i) { 900cb93a386Sopenharmony_ci SkASSERT(planes[i].colorType() == kAlpha_8_SkColorType); 901cb93a386Sopenharmony_ci SkASSERT(info.planeInfo(i) == planes[i].info()); 902cb93a386Sopenharmony_ci } 903cb93a386Sopenharmony_ci } 904cb93a386Sopenharmony_ci#endif 905cb93a386Sopenharmony_ci 906cb93a386Sopenharmony_ci // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has 907cb93a386Sopenharmony_ci // a 2-D array of pixels for each of the components (Y, U, V) in the image. 908cb93a386Sopenharmony_ci // Cheat Sheet: 909cb93a386Sopenharmony_ci // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE*** 910cb93a386Sopenharmony_ci JSAMPARRAY yuv[3]; 911cb93a386Sopenharmony_ci 912cb93a386Sopenharmony_ci // Set aside enough space for pointers to rows of Y, U, and V. 913cb93a386Sopenharmony_ci JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE]; 914cb93a386Sopenharmony_ci yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE) 915cb93a386Sopenharmony_ci yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE) 916cb93a386Sopenharmony_ci yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE) 917cb93a386Sopenharmony_ci 918cb93a386Sopenharmony_ci // Initialize rowptrs. 919cb93a386Sopenharmony_ci int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor; 920cb93a386Sopenharmony_ci static_assert(sizeof(JSAMPLE) == 1); 921cb93a386Sopenharmony_ci for (int i = 0; i < numYRowsPerBlock; i++) { 922cb93a386Sopenharmony_ci rowptrs[i] = static_cast<JSAMPLE*>(planes[0].writable_addr()) + i* planes[0].rowBytes(); 923cb93a386Sopenharmony_ci } 924cb93a386Sopenharmony_ci for (int i = 0; i < DCTSIZE; i++) { 925cb93a386Sopenharmony_ci rowptrs[i + 2 * DCTSIZE] = 926cb93a386Sopenharmony_ci static_cast<JSAMPLE*>(planes[1].writable_addr()) + i* planes[1].rowBytes(); 927cb93a386Sopenharmony_ci rowptrs[i + 3 * DCTSIZE] = 928cb93a386Sopenharmony_ci static_cast<JSAMPLE*>(planes[2].writable_addr()) + i* planes[2].rowBytes(); 929cb93a386Sopenharmony_ci } 930cb93a386Sopenharmony_ci 931cb93a386Sopenharmony_ci // After each loop iteration, we will increment pointers to Y, U, and V. 932cb93a386Sopenharmony_ci size_t blockIncrementY = numYRowsPerBlock * planes[0].rowBytes(); 933cb93a386Sopenharmony_ci size_t blockIncrementU = DCTSIZE * planes[1].rowBytes(); 934cb93a386Sopenharmony_ci size_t blockIncrementV = DCTSIZE * planes[2].rowBytes(); 935cb93a386Sopenharmony_ci 936cb93a386Sopenharmony_ci uint32_t numRowsPerBlock = numYRowsPerBlock; 937cb93a386Sopenharmony_ci 938cb93a386Sopenharmony_ci // We intentionally round down here, as this first loop will only handle 939cb93a386Sopenharmony_ci // full block rows. As a special case at the end, we will handle any 940cb93a386Sopenharmony_ci // remaining rows that do not make up a full block. 941cb93a386Sopenharmony_ci const int numIters = dinfo->output_height / numRowsPerBlock; 942cb93a386Sopenharmony_ci for (int i = 0; i < numIters; i++) { 943cb93a386Sopenharmony_ci JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); 944cb93a386Sopenharmony_ci if (linesRead < numRowsPerBlock) { 945cb93a386Sopenharmony_ci // FIXME: Handle incomplete YUV decodes without signalling an error. 946cb93a386Sopenharmony_ci return kInvalidInput; 947cb93a386Sopenharmony_ci } 948cb93a386Sopenharmony_ci 949cb93a386Sopenharmony_ci // Update rowptrs. 950cb93a386Sopenharmony_ci for (int j = 0; j < numYRowsPerBlock; j++) { 951cb93a386Sopenharmony_ci rowptrs[j] += blockIncrementY; 952cb93a386Sopenharmony_ci } 953cb93a386Sopenharmony_ci for (int j = 0; j < DCTSIZE; j++) { 954cb93a386Sopenharmony_ci rowptrs[j + 2 * DCTSIZE] += blockIncrementU; 955cb93a386Sopenharmony_ci rowptrs[j + 3 * DCTSIZE] += blockIncrementV; 956cb93a386Sopenharmony_ci } 957cb93a386Sopenharmony_ci } 958cb93a386Sopenharmony_ci 959cb93a386Sopenharmony_ci uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline; 960cb93a386Sopenharmony_ci SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock); 961cb93a386Sopenharmony_ci SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock); 962cb93a386Sopenharmony_ci if (remainingRows > 0) { 963cb93a386Sopenharmony_ci // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill 964cb93a386Sopenharmony_ci // this requirement using an extra row buffer. 965cb93a386Sopenharmony_ci // FIXME: Should SkCodec have an extra memory buffer that can be shared among 966cb93a386Sopenharmony_ci // all of the implementations that use temporary/garbage memory? 967cb93a386Sopenharmony_ci SkAutoTMalloc<JSAMPLE> extraRow(planes[0].rowBytes()); 968cb93a386Sopenharmony_ci for (int i = remainingRows; i < numYRowsPerBlock; i++) { 969cb93a386Sopenharmony_ci rowptrs[i] = extraRow.get(); 970cb93a386Sopenharmony_ci } 971cb93a386Sopenharmony_ci int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters; 972cb93a386Sopenharmony_ci for (int i = remainingUVRows; i < DCTSIZE; i++) { 973cb93a386Sopenharmony_ci rowptrs[i + 2 * DCTSIZE] = extraRow.get(); 974cb93a386Sopenharmony_ci rowptrs[i + 3 * DCTSIZE] = extraRow.get(); 975cb93a386Sopenharmony_ci } 976cb93a386Sopenharmony_ci 977cb93a386Sopenharmony_ci JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); 978cb93a386Sopenharmony_ci if (linesRead < remainingRows) { 979cb93a386Sopenharmony_ci // FIXME: Handle incomplete YUV decodes without signalling an error. 980cb93a386Sopenharmony_ci return kInvalidInput; 981cb93a386Sopenharmony_ci } 982cb93a386Sopenharmony_ci } 983cb93a386Sopenharmony_ci 984cb93a386Sopenharmony_ci return kSuccess; 985cb93a386Sopenharmony_ci} 986cb93a386Sopenharmony_ci 987cb93a386Sopenharmony_ci// This function is declared in SkJpegInfo.h, used by SkPDF. 988cb93a386Sopenharmony_cibool SkGetJpegInfo(const void* data, size_t len, 989cb93a386Sopenharmony_ci SkISize* size, 990cb93a386Sopenharmony_ci SkEncodedInfo::Color* colorType, 991cb93a386Sopenharmony_ci SkEncodedOrigin* orientation) { 992cb93a386Sopenharmony_ci if (!SkJpegCodec::IsJpeg(data, len)) { 993cb93a386Sopenharmony_ci return false; 994cb93a386Sopenharmony_ci } 995cb93a386Sopenharmony_ci 996cb93a386Sopenharmony_ci SkMemoryStream stream(data, len); 997cb93a386Sopenharmony_ci JpegDecoderMgr decoderMgr(&stream); 998cb93a386Sopenharmony_ci // libjpeg errors will be caught and reported here 999cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(decoderMgr.errorMgr()); 1000cb93a386Sopenharmony_ci if (setjmp(jmp)) { 1001cb93a386Sopenharmony_ci return false; 1002cb93a386Sopenharmony_ci } 1003cb93a386Sopenharmony_ci decoderMgr.init(); 1004cb93a386Sopenharmony_ci jpeg_decompress_struct* dinfo = decoderMgr.dinfo(); 1005cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kExifMarker, 0xFFFF); 1006cb93a386Sopenharmony_ci jpeg_save_markers(dinfo, kICCMarker, 0xFFFF); 1007cb93a386Sopenharmony_ci if (JPEG_HEADER_OK != jpeg_read_header(dinfo, true)) { 1008cb93a386Sopenharmony_ci return false; 1009cb93a386Sopenharmony_ci } 1010cb93a386Sopenharmony_ci SkEncodedInfo::Color encodedColorType; 1011cb93a386Sopenharmony_ci if (!decoderMgr.getEncodedColor(&encodedColorType)) { 1012cb93a386Sopenharmony_ci return false; // Unable to interpret the color channels as colors. 1013cb93a386Sopenharmony_ci } 1014cb93a386Sopenharmony_ci if (colorType) { 1015cb93a386Sopenharmony_ci *colorType = encodedColorType; 1016cb93a386Sopenharmony_ci } 1017cb93a386Sopenharmony_ci if (orientation) { 1018cb93a386Sopenharmony_ci *orientation = get_exif_orientation(dinfo); 1019cb93a386Sopenharmony_ci } 1020cb93a386Sopenharmony_ci if (size) { 1021cb93a386Sopenharmony_ci *size = {SkToS32(dinfo->image_width), SkToS32(dinfo->image_height)}; 1022cb93a386Sopenharmony_ci } 1023cb93a386Sopenharmony_ci return true; 1024cb93a386Sopenharmony_ci} 1025