公司网站开发背景,wordpress底部信息修改,wordpress 命令执行,2022年装修效果图大全解码区域
1,抽象
1,图片很大时,解码速度缓慢,占用内存很高,并且,图片超过一定尺寸时,无法上传和显示纹理(这跟GPU能力有关,一般的GPU是8192*8192).这时只好下采样,但会牺牲图片显示质量.
2,-对图库等,需要清晰浏览图片的应用,不可能设置下采样率来解决这一问题,因此,Google加…解码区域
1,抽象
1,图片很大时,解码速度缓慢,占用内存很高,并且,图片超过一定尺寸时,无法上传和显示纹理(这跟GPU能力有关,一般的GPU是8192*8192).这时只好下采样,但会牺牲图片显示质量.
2,-对图库等,需要清晰浏览图片的应用,不可能设置下采样率来解决这一问题,因此,Google加入了解码区域功能,这样可从原始图片文件中,解码出一部分完整区域图片内容.
3,解码区域难点主要在,定位像素区域所对应的文件位置,需要图像编码有一定的连续性,所幸,主流图像格式都是如此.
4,目前解码区域主要实现了png,jpeg,webp类型图片的支持.本篇,介绍最常用的jpeg格式的解码区域实现.
2,解码区域总流程
在框架侧创建BitmapRegionDecoder时,创建对应类型的SkImageDecoder来扫描全文件,调用其onBuildTileIndex方法构建tileIndex,嵌入在其关联的SkImageDecoder之中,在后续调用decodeRegion时,使用SkImageDecoder的onDecodeSubset方法来解码区域.
3,Jpeg的解码区域
#ifdef SK_BUILD_FOR_ANDROID
bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {SkAutoTDeleteSkJPEGImageIndex imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));jpeg_decompress_struct* cinfo imageIndex-cinfo();skjpeg_error_mgr sk_err;set_error_mgr(cinfo, sk_err);//在调用此setjmp前,实例化所有对象,以便在错误时正确清理它们.if (setjmp(sk_err.fJmpBuf)) {return false;}//创建,来创建/构建HuffmanIndex的cinfoif (!imageIndex-initializeInfoAndReadHeader()) {return false;}if (!imageIndex-buildHuffmanIndex()) {return false;}//析构,来创建/构建霍夫曼索引的cinfoimageIndex-destroyInfo();//初化解码器到图像解码模式if (!imageIndex-initializeInfoAndReadHeader()) {return false;}//FIXME:这设置了cinfo-out_color_space,稍后可能会根据onDecodeSubset中的配置更改它.这应该没问题,因为在(它调用jinit_color_deconverter时)更改它后,jpeg_init_read_tile_scanline调用再次检查out_color_space.(void) this-getBitmapColorType(cinfo);turn_off_visual_optimizations(cinfo);//不是jpeg_start_decompress(),而开始平铺解压缩if (!imageIndex-startTileDecompress()) {return false;}SkASSERT(1 cinfo-scale_num);fImageWidth cinfo-output_width;fImageHeight cinfo-output_height;if (width) {*width fImageWidth;}if (height) {*height fImageHeight;}SkDELETE(fImageIndex);fImageIndex imageIndex.detach();return true;
}
bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect region) {if (NULL fImageIndex) {return false;}jpeg_decompress_struct* cinfo fImageIndex-cinfo();SkIRect rect SkIRect::MakeWH(fImageWidth, fImageHeight);if (!rect.intersect(region)) {//如果请求区域,完全在图像外,则返回falsereturn false;}skjpeg_error_mgr errorManager;set_error_mgr(cinfo, errorManager);if (setjmp(errorManager.fJmpBuf)) {return false;}int requestedSampleSize this-getSampleSize();cinfo-scale_denom requestedSampleSize;set_dct_method(*this, cinfo);const SkColorType colorType this-getBitmapColorType(cinfo);adjust_out_color_space_and_dither(cinfo, colorType, *this);int startX rect.fLeft;int startY rect.fTop;int width rect.width();int height rect.height();jpeg_init_read_tile_scanline(cinfo, fImageIndex-huffmanIndex(), startX, startY, width, height);int skiaSampleSize recompute_sampleSize(requestedSampleSize, *cinfo);int actualSampleSize skiaSampleSize * (DCTSIZE / cinfo-min_DCT_scaled_size);SkScaledBitmapSampler sampler(width, height, skiaSampleSize);SkBitmap bitmap;//假设A8位图不透明,以避免检查每个单独的像素.它不太可能是不透明的,因为不透明的A8位图不会很有趣.否则,jpeg图像是不透明的.bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType, kAlpha_8_SkColorType colorType ? kPremul_SkAlphaType : kOpaque_SkAlphaType));//提前检查是否可交换(dest,src).如果是,则坚持使用AllocPixelRef,因为交换时它更便宜.如果否,则使用alloc来分配像素以避免垃集. int w rect.width() / actualSampleSize;int h rect.height() / actualSampleSize;bool swapOnly (rect region) bm-isNull() (w bitmap.width()) (h bitmap.height()) ((startX - rect.x()) / actualSampleSize 0) ((startY - rect.y()) / actualSampleSize 0);if (swapOnly) {if (!this-allocPixelRef(bitmap, NULL)) {return return_false(*cinfo, bitmap, allocPixelRef);}} else {if (!bitmap.allocPixels()) {return return_false(*cinfo, bitmap, allocPixels);}}SkAutoLockPixels alp(bitmap);
#ifdef ANDROID_RGB/*如果可能,请短路SkScaledBitmapSampler,因为这会显著提高性能.*/if (skiaSampleSize 1 ((kN32_SkColorType colorType cinfo-out_color_space JCS_RGBA_8888) ||(kRGB_565_SkColorType colorType cinfo-out_color_space JCS_RGB_565))){JSAMPLE* rowptr (JSAMPLE*)bitmap.getPixels();INT32 const bpr bitmap.rowBytes();int rowTotalCount 0;while (rowTotalCount height) {int rowCount jpeg_read_tile_scanline(cinfo, fImageIndex-huffmanIndex(), rowptr);//如果rowCount0,则没有得到扫描行,所以中止.onDecodeSubset()依赖onBuildTileIndex(),它需要完整的映射才能成功. if (0 rowCount) {return return_false(*cinfo, bitmap, read_scanlines);}if (this-shouldCancelDecode()) {return return_false(*cinfo, bitmap, shouldCancelDecode);}rowTotalCount rowCount;rowptr bpr;}if (swapOnly) {bm-swap(bitmap);} else {cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(), region.width(), region.height(), startX, startY);}return true;}
#endif//检查支持的格式SkScaledBitmapSampler::SrcConfig sc;int srcBytesPerPixel;if (!get_src_config(*cinfo, sc, srcBytesPerPixel)) {return return_false(*cinfo, *bm, jpeg colorspace);}if (!sampler.begin(bitmap, sc, *this)) {return return_false(*cinfo, bitmap, sampler.begin);}SkAutoMalloc srcStorage(width * srcBytesPerPixel);uint8_t* srcRow (uint8_t*)srcStorage.get();//可能跳过初始行[sampler.srcY0]if (!skip_src_rows_tile(cinfo, fImageIndex-huffmanIndex(), srcRow, sampler.srcY0())) {return return_false(*cinfo, bitmap, skip rows);}//现在遍历扫描行,直到ybitmap-height()-1for (int y 0;; y) {JSAMPLE* rowptr (JSAMPLE*)srcRow;int row_count jpeg_read_tile_scanline(cinfo, fImageIndex-huffmanIndex(), rowptr);//如果row_count0,则没有得到扫描行,所以中止.onDecodeSubset()依赖onBuildTileIndex(),它需要完整的映射才能成功. if (0 row_count) {return return_false(*cinfo, bitmap, read_scanlines);}if (this-shouldCancelDecode()) {return return_false(*cinfo, bitmap, shouldCancelDecode);}if (JCS_CMYK cinfo-out_color_space) {convert_CMYK_to_RGB(srcRow, width);}sampler.next(srcRow);if (bitmap.height() - 1 y) {//大功告成break;}if (!skip_src_rows_tile(cinfo, fImageIndex-huffmanIndex(), srcRow, sampler.srcDY() - 1)) {return return_false(*cinfo, bitmap, skip rows);}}if (swapOnly) {bm-swap(bitmap);} else {cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),region.width(), region.height(), startX, startY);}return true;
}
#endif在onBuildTileIndex时,创建了huffman_index,其中的内容主要是一系列,记录每个块对应偏移的huffman_offset. 解码时,先移到对应块位置,然后解出像素.
GLOBAL(JDIMENSION)
jpeg_read_tile_scanline (j_decompress_ptr cinfo, huffman_index *index, JSAMPARRAY scanlines)
{//计算iMCU的边界int lines_per_iMCU_row cinfo-max_v_samp_factor * DCTSIZE;int lines_per_iMCU_col cinfo-max_h_samp_factor * DCTSIZE;int sample_size DCTSIZE / cinfo-min_DCT_scaled_size;JDIMENSION row_ctr 0;if (cinfo-progressive_mode) {(*cinfo-main-process_data) (cinfo, scanlines, row_ctr, 1);} else {if (cinfo-output_scanline % (lines_per_iMCU_row / sample_size) 0) {//读头设置到下一个iMCU行int iMCU_row_offset cinfo-output_scanline / (lines_per_iMCU_row / sample_size);int offset_data_col_position cinfo-coef-MCU_column_left_boundary /index-MCU_sample_size;huffman_offset_data offset_data index-scan[0].offset[iMCU_row_offset][offset_data_col_position];(*cinfo-entropy-configure_huffman_decoder) (cinfo, offset_data);}(*cinfo-main-process_data) (cinfo, scanlines, row_ctr, 1);}cinfo-output_scanline row_ctr;return row_ctr;
}