From: DRC Date: Mon, 12 May 2014 09:23:57 +0000 (+0000) Subject: Add support for decompressing to RGB565 (16-bit) pixels X-Git-Tag: 1.3.90~67 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=78df2e6115b0e579432d01cb034132cd4402a1ba;p=libjpeg-turbo Add support for decompressing to RGB565 (16-bit) pixels git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@1295 632fc199-4ca6-4c93-a231-07263d6284db --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 40e1433..307c495 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,15 +285,21 @@ enable_testing() set(MD5_JPEG_RGB_ISLOW 768e970dd57b340ff1b83c9d3d47c77b) set(MD5_PPM_RGB_ISLOW 00a257f5393fef8821f2b88ac7421291) +set(MD5_BMP_RGB_ISLOW_565 f07d2e75073e4bb10f6c6f4d36e2e3be) +set(MD5_BMP_RGB_ISLOW_565D 4cfa0928ef3e6bb626d7728c924cfda4) set(MD5_JPEG_422_IFAST_OPT 2540287b79d913f91665e660303ab2c8) set(MD5_PPM_422_IFAST 35bd6b3f833bad23de82acea847129fa) set(MD5_PPM_422M_IFAST 8dbc65323d62cca7c91ba02dd1cfa81d) +set(MD5_BMP_422M_IFAST_565 3294bd4d9a1f2b3d08ea6020d0db7065) +set(MD5_BMP_422M_IFAST_565D da98c9c7b6039511be4a79a878a9abc1) set(MD5_JPEG_420_IFAST_Q100_PROG 990cbe0329c882420a2094da7e5adade) set(MD5_PPM_420_Q100_IFAST 5a732542015c278ff43635e473a8a294) set(MD5_PPM_420M_Q100_IFAST ff692ee9323a3b424894862557c092f1) set(MD5_JPEG_GRAY_ISLOW 72b51f894b8f4a10b3ee3066770aa38d) set(MD5_PPM_GRAY_ISLOW 8d3596c56eace32f205deccc229aa5ed) -set(MD5_PPM_GRAY_RGB_ISLOW 116424ac07b79e5e801f00508eab48ec) +set(MD5_PPM_GRAY_ISLOW_RGB 116424ac07b79e5e801f00508eab48ec) +set(MD5_BMP_GRAY_ISLOW_565 12f78118e56a2f48b966f792fedf23cc) +set(MD5_BMP_GRAY_ISLOW_565D bdbbd616441a24354c98553df5dc82db) set(MD5_JPEG_420S_IFAST_OPT 388708217ac46273ca33086b22827ed8) if(WITH_SIMD) set(MD5_JPEG_3x2_FLOAT_PROG 343e3f8caf8af5986ebaf0bdc13b5c71) @@ -319,6 +325,10 @@ set(MD5_PPM_420M_ISLOW_3_8 79eca9175652ced755155c90e785a996) set(MD5_PPM_420M_ISLOW_1_4 79cd778f8bf1a117690052cacdd54eca) set(MD5_PPM_420M_ISLOW_1_8 391b3d4aca640c8567d6f8745eb2142f) set(MD5_BMP_420_ISLOW_256 4980185e3776e89bd931736e1cddeee6) +set(MD5_BMP_420_ISLOW_565 bf9d13e16c4923b92e1faa604d7922cb) +set(MD5_BMP_420_ISLOW_565D 6bde71526acc44bcff76f696df8638d2) +set(MD5_BMP_420M_ISLOW_565 8dc0185245353cfa32ad97027342216f) +set(MD5_BMP_420M_ISLOW_565D d1be3a3339166255e76fa50a0d70d73e) set(MD5_JPEG_CROP b4197f377e621c4e9b1d20471432610d) if(WITH_JAVA) @@ -379,6 +389,22 @@ foreach(libtype shared static) add_test(djpeg${suffix}-rgb-islow-cmp ${CMAKE_COMMAND} -DMD5=${MD5_PPM_RGB_ISLOW} -DFILE=testout_rgb_islow.ppm -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: RGB->RGB565 SAMP: fullsize IDCT: islow ENT: huff + add_test(djpeg${suffix}-rgb-islow-565 + ${dir}djpeg${suffix} -dct int -rgb565 -dither none -bmp + -outfile testout_rgb_islow_565.bmp testout_rgb_islow.jpg) + add_test(djpeg${suffix}-rgb-islow-565-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_RGB_ISLOW_565} + -DFILE=testout_rgb_islow_565.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: RGB->RGB565 (dithered) SAMP: fullsize IDCT: islow ENT: huff + add_test(djpeg${suffix}-rgb-islow-565D + ${dir}djpeg${suffix} -dct int -rgb565 -bmp + -outfile testout_rgb_islow_565D.bmp testout_rgb_islow.jpg) + add_test(djpeg${suffix}-rgb-islow-565D-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_RGB_ISLOW_565D} + -DFILE=testout_rgb_islow_565D.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) # CC: RGB->YCC SAMP: fullsize/h2v1 FDCT: ifast ENT: 2-pass huff add_test(cjpeg${suffix}-422-ifast-opt @@ -398,15 +424,31 @@ foreach(libtype shared static) -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) # CC: YCC->RGB SAMP: h2v1 merged IDCT: ifast ENT: huff add_test(djpeg${suffix}-422m-ifast - ${dir}djpeg${suffix} -nosmooth -dct fast -outfile testout_422m_ifast.ppm + ${dir}djpeg${suffix} -dct fast -nosmooth -outfile testout_422m_ifast.ppm testout_422_ifast_opt.jpg) add_test(djpeg${suffix}-422m-ifast-cmp ${CMAKE_COMMAND} -DMD5=${MD5_PPM_422M_IFAST} -DFILE=testout_422m_ifast.ppm -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: YCC->RGB565 SAMP: h2v1 merged IDCT: ifast ENT: huff + add_test(djpeg${suffix}-422m-ifast-565 + ${dir}djpeg${suffix} -dct int -nosmooth -rgb565 -dither none -bmp + -outfile testout_422m_ifast_565.bmp testout_422_ifast_opt.jpg) + add_test(djpeg${suffix}-422m-ifast-565-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_422M_IFAST_565} + -DFILE=testout_422m_ifast_565.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: YCC->RGB565 (dithered) SAMP: h2v1 merged IDCT: ifast ENT: huff + add_test(djpeg${suffix}-422m-ifast-565D + ${dir}djpeg${suffix} -dct int -nosmooth -rgb565 -bmp + -outfile testout_422m_ifast_565D.bmp testout_422_ifast_opt.jpg) + add_test(djpeg${suffix}-422m-ifast-565D-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_422M_IFAST_565D} + -DFILE=testout_422m_ifast_565D.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) # CC: RGB->YCC SAMP: fullsize/h2v2 FDCT: ifast ENT: prog huff add_test(cjpeg${suffix}-420-q100-ifast-prog - ${dir}cjpeg${suffix} -sample 2x2 -dct fast -quality 100 -prog + ${dir}cjpeg${suffix} -sample 2x2 -quality 100 -dct fast -prog -outfile testout_420_q100_ifast_prog.jpg ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm) add_test(cjpeg${suffix}-420-q100-ifast-prog-cmp @@ -423,7 +465,7 @@ foreach(libtype shared static) -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) # CC: YCC->RGB SAMP: h2v2 merged IDCT: ifast ENT: prog huff add_test(djpeg${suffix}-420m-q100-ifast-prog - ${dir}djpeg${suffix} -nosmooth -dct fast + ${dir}djpeg${suffix} -dct fast -nosmooth -outfile testout_420m_q100_ifast.ppm testout_420_q100_ifast_prog.jpg) add_test(djpeg${suffix}-420m-q100-ifast-prog-cmp ${CMAKE_COMMAND} -DMD5=${MD5_PPM_420M_Q100_IFAST} @@ -438,7 +480,7 @@ foreach(libtype shared static) ${CMAKE_COMMAND} -DMD5=${MD5_JPEG_GRAY_ISLOW} -DFILE=testout_gray_islow.jpg -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) - # CC: Gray->Gray SAMP: fullsize FDCT: islow ENT: huff + # CC: Gray->Gray SAMP: fullsize IDCT: islow ENT: huff add_test(djpeg${suffix}-gray-islow ${dir}djpeg${suffix} -dct int -outfile testout_gray_islow.ppm testout_gray_islow.jpg) @@ -446,13 +488,29 @@ foreach(libtype shared static) ${CMAKE_COMMAND} -DMD5=${MD5_PPM_GRAY_ISLOW} -DFILE=testout_gray_islow.ppm -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) - # CC: Gray->RGB SAMP: fullsize FDCT: islow ENT: huff - add_test(djpeg${suffix}-gray-rgb-islow - ${dir}djpeg${suffix} -rgb -dct int -outfile testout_gray_rgb_islow.ppm + # CC: Gray->RGB SAMP: fullsize IDCT: islow ENT: huff + add_test(djpeg${suffix}-gray-islow-rgb + ${dir}djpeg${suffix} -dct int -rgb -outfile testout_gray_islow_rgb.ppm testout_gray_islow.jpg) - add_test(cjpeg${suffix}-gray-rgb-islow-cmp - ${CMAKE_COMMAND} -DMD5=${MD5_PPM_GRAY_RGB_ISLOW} - -DFILE=testout_gray_rgb_islow.ppm + add_test(cjpeg${suffix}-gray-islow-rgb-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_PPM_GRAY_ISLOW_RGB} + -DFILE=testout_gray_islow_rgb.ppm + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: Gray->RGB565 SAMP: fullsize IDCT: islow ENT: huff + add_test(djpeg${suffix}-gray-islow-565 + ${dir}djpeg${suffix} -dct int -rgb565 -dither none -bmp + -outfile testout_gray_islow_565.bmp testout_gray_islow.jpg) + add_test(djpeg${suffix}-gray-islow-565-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_GRAY_ISLOW_565} + -DFILE=testout_gray_islow_565.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: Gray->RGB565 (dithered) SAMP: fullsize IDCT: islow ENT: huff + add_test(djpeg${suffix}-gray-islow-565D + ${dir}djpeg${suffix} -dct int -rgb565 -bmp + -outfile testout_gray_islow_565D.bmp testout_gray_islow.jpg) + add_test(djpeg${suffix}-gray-islow-565D-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_GRAY_ISLOW_565D} + -DFILE=testout_gray_islow_565D.bmp -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) # CC: RGB->YCC SAMP: fullsize smooth/h2v2 smooth FDCT: islow @@ -502,7 +560,7 @@ foreach(libtype shared static) -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) # CC: YCC->RGB SAMP: fullsize FDCT: islow ENT: prog arith add_test(cjpeg${suffix}-444-islow-progari - ${dir}cjpeg${suffix} -dct int -progressive -arithmetic -sample 1x1 + ${dir}cjpeg${suffix} -sample 1x1 -dct int -progressive -arithmetic -outfile testout_444_islow_progari.jpg ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm) add_test(cjpeg${suffix}-444-islow-progari-cmp @@ -550,7 +608,7 @@ foreach(libtype shared static) foreach(scale 2_1 15_8 13_8 11_8 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8) string(REGEX REPLACE "_" "/" scalearg ${scale}) add_test(djpeg${suffix}-420m-islow-${scale} - ${dir}djpeg${suffix} -dct int -nosmooth -scale ${scalearg} -ppm + ${dir}djpeg${suffix} -dct int -scale ${scalearg} -nosmooth -ppm -outfile testout_420m_islow_${scale}.ppm ${CMAKE_SOURCE_DIR}/testimages/testorig.jpg) add_test(djpeg${suffix}-420m-islow-${scale}-cmp @@ -561,13 +619,49 @@ foreach(libtype shared static) # CC: YCC->RGB (dithered) SAMP: h2v2 fancy IDCT: islow ENT: huff add_test(djpeg${suffix}-420-islow-256 - ${dir}djpeg${suffix} -dct int -bmp -colors 256 + ${dir}djpeg${suffix} -dct int -colors 256 -bmp -outfile testout_420_islow_256.bmp ${CMAKE_SOURCE_DIR}/testimages/testorig.jpg) add_test(djpeg${suffix}-420-islow-256-cmp ${CMAKE_COMMAND} -DMD5=${MD5_BMP_420_ISLOW_256} -DFILE=testout_420_islow_256.bmp -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: YCC->RGB565 SAMP: h2v2 fancy IDCT: islow ENT: huff + add_test(djpeg${suffix}-420-islow-565 + ${dir}djpeg${suffix} -dct int -rgb565 -dither none -bmp + -outfile testout_420_islow_565.bmp + ${CMAKE_SOURCE_DIR}/testimages/testorig.jpg) + add_test(djpeg${suffix}-420-islow-565-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_420_ISLOW_565} + -DFILE=testout_420_islow_565.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: YCC->RGB565 (dithered) SAMP: h2v2 fancy IDCT: islow ENT: huff + add_test(djpeg${suffix}-420-islow-565D + ${dir}djpeg${suffix} -dct int -rgb565 -bmp + -outfile testout_420_islow_565D.bmp + ${CMAKE_SOURCE_DIR}/testimages/testorig.jpg) + add_test(djpeg${suffix}-420-islow-565D-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_420_ISLOW_565D} + -DFILE=testout_420_islow_565D.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: YCC->RGB565 SAMP: h2v2 merged IDCT: islow ENT: huff + add_test(djpeg${suffix}-420m-islow-565 + ${dir}djpeg${suffix} -dct int -nosmooth -rgb565 -dither none -bmp + -outfile testout_420m_islow_565.bmp + ${CMAKE_SOURCE_DIR}/testimages/testorig.jpg) + add_test(djpeg${suffix}-420m-islow-565-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_420M_ISLOW_565} + -DFILE=testout_420m_islow_565.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) + # CC: YCC->RGB565 (dithered) SAMP: h2v2 merged IDCT: islow ENT: huff + add_test(djpeg${suffix}-420m-islow-565D + ${dir}djpeg${suffix} -dct int -nosmooth -rgb565 -bmp + -outfile testout_420m_islow_565D.bmp + ${CMAKE_SOURCE_DIR}/testimages/testorig.jpg) + add_test(djpeg${suffix}-420m-islow-565D-cmp + ${CMAKE_COMMAND} -DMD5=${MD5_BMP_420M_ISLOW_565D} + -DFILE=testout_420m_islow_565D.bmp + -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake) add_test(jpegtran${suffix}-crop ${dir}jpegtran${suffix} -crop 120x90+20+50 -transpose -perfect diff --git a/ChangeLog.txt b/ChangeLog.txt index f68a988..e59939f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -62,6 +62,9 @@ mainly a legacy feature. They generally do not produce significantly better accuracy than the slow integer DCT/IDCT algorithms, and they are quite a bit slower. +[8] Added a new output colorspace (JCS_RGB565) to the libjpeg API that allows +for decompressing JPEG images into RGB565 (16-bit) pixels. + 1.3.1 ===== diff --git a/Makefile.am b/Makefile.am index 1844672..cee54eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -155,7 +155,7 @@ dist_example_DATA = example.c EXTRA_DIST = win release $(DOCS) testimages CMakeLists.txt \ sharedlib/CMakeLists.txt cmakescripts libjpeg.map.in doc doxygen.config \ - jccolext.c jdcolext.c jdmrgext.c jstdhuff.c + jccolext.c jdcolext.c jdcol565.c jdmrgext.c jstdhuff.c dist-hook: rm -rf `find $(distdir) -name .svn` @@ -165,15 +165,21 @@ SUBDIRS += md5 MD5_JPEG_RGB_ISLOW = 768e970dd57b340ff1b83c9d3d47c77b MD5_PPM_RGB_ISLOW = 00a257f5393fef8821f2b88ac7421291 +MD5_BMP_RGB_ISLOW_565 = f07d2e75073e4bb10f6c6f4d36e2e3be +MD5_BMP_RGB_ISLOW_565D = 4cfa0928ef3e6bb626d7728c924cfda4 MD5_JPEG_422_IFAST_OPT = 2540287b79d913f91665e660303ab2c8 MD5_PPM_422_IFAST = 35bd6b3f833bad23de82acea847129fa MD5_PPM_422M_IFAST = 8dbc65323d62cca7c91ba02dd1cfa81d +MD5_BMP_422M_IFAST_565 = 3294bd4d9a1f2b3d08ea6020d0db7065 +MD5_BMP_422M_IFAST_565D = da98c9c7b6039511be4a79a878a9abc1 MD5_JPEG_420_IFAST_Q100_PROG = 990cbe0329c882420a2094da7e5adade MD5_PPM_420_Q100_IFAST = 5a732542015c278ff43635e473a8a294 MD5_PPM_420M_Q100_IFAST = ff692ee9323a3b424894862557c092f1 MD5_JPEG_GRAY_ISLOW = 72b51f894b8f4a10b3ee3066770aa38d MD5_PPM_GRAY_ISLOW = 8d3596c56eace32f205deccc229aa5ed -MD5_PPM_GRAY_RGB_ISLOW = 116424ac07b79e5e801f00508eab48ec +MD5_PPM_GRAY_ISLOW_RGB = 116424ac07b79e5e801f00508eab48ec +MD5_BMP_GRAY_ISLOW_565 = 12f78118e56a2f48b966f792fedf23cc +MD5_BMP_GRAY_ISLOW_565D = bdbbd616441a24354c98553df5dc82db MD5_JPEG_420S_IFAST_OPT = 388708217ac46273ca33086b22827ed8 # See README-turbo.txt for more details on why this next bit is necessary. if WITH_SSE_FLOAT_DCT @@ -200,6 +206,10 @@ MD5_PPM_420M_ISLOW_3_8 = 79eca9175652ced755155c90e785a996 MD5_PPM_420M_ISLOW_1_4 = 79cd778f8bf1a117690052cacdd54eca MD5_PPM_420M_ISLOW_1_8 = 391b3d4aca640c8567d6f8745eb2142f MD5_BMP_420_ISLOW_256 = 4980185e3776e89bd931736e1cddeee6 +MD5_BMP_420_ISLOW_565 = bf9d13e16c4923b92e1faa604d7922cb +MD5_BMP_420_ISLOW_565D = 6bde71526acc44bcff76f696df8638d2 +MD5_BMP_420M_ISLOW_565 = 8dc0185245353cfa32ad97027342216f +MD5_BMP_420M_ISLOW_565D =d1be3a3339166255e76fa50a0d70d73e MD5_JPEG_CROP = b4197f377e621c4e9b1d20471432610d test: testclean all @@ -230,7 +240,15 @@ endif # CC: null SAMP: fullsize IDCT: islow ENT: huff ./djpeg -dct int -ppm -outfile testout_rgb_islow.ppm testout_rgb_islow.jpg md5/md5cmp $(MD5_PPM_RGB_ISLOW) testout_rgb_islow.ppm - rm testout_rgb_islow.ppm testout_rgb_islow.jpg + rm testout_rgb_islow.ppm +# CC: RGB->RGB565 SAMP: fullsize IDCT: islow ENT: huff + ./djpeg -dct int -rgb565 -dither none -bmp -outfile testout_rgb_islow_565.bmp testout_rgb_islow.jpg + md5/md5cmp $(MD5_BMP_RGB_ISLOW_565) testout_rgb_islow_565.bmp + rm testout_rgb_islow_565.bmp +# CC: RGB->RGB565 (dithered) SAMP: fullsize IDCT: islow ENT: huff + ./djpeg -dct int -rgb565 -bmp -outfile testout_rgb_islow_565D.bmp testout_rgb_islow.jpg + md5/md5cmp $(MD5_BMP_RGB_ISLOW_565D) testout_rgb_islow_565D.bmp + rm testout_rgb_islow_565D.bmp testout_rgb_islow.jpg # CC: RGB->YCC SAMP: fullsize/h2v1 FDCT: ifast ENT: 2-pass huff ./cjpeg -sample 2x1 -dct fast -opt -outfile testout_422_ifast_opt.jpg $(srcdir)/testimages/testorig.ppm @@ -240,33 +258,49 @@ endif md5/md5cmp $(MD5_PPM_422_IFAST) testout_422_ifast.ppm rm testout_422_ifast.ppm # CC: YCC->RGB SAMP: h2v1 merged IDCT: ifast ENT: huff - ./djpeg -nosmooth -dct fast -outfile testout_422m_ifast.ppm testout_422_ifast_opt.jpg + ./djpeg -dct fast -nosmooth -outfile testout_422m_ifast.ppm testout_422_ifast_opt.jpg md5/md5cmp $(MD5_PPM_422M_IFAST) testout_422m_ifast.ppm - rm testout_422m_ifast.ppm testout_422_ifast_opt.jpg + rm testout_422m_ifast.ppm +# CC: YCC->RGB565 SAMP: h2v1 merged IDCT: ifast ENT: huff + ./djpeg -dct int -nosmooth -rgb565 -dither none -bmp -outfile testout_422m_ifast_565.bmp testout_422_ifast_opt.jpg + md5/md5cmp $(MD5_BMP_422M_IFAST_565) testout_422m_ifast_565.bmp + rm testout_422m_ifast_565.bmp +# CC: YCC->RGB565 (dithered) SAMP: h2v1 merged IDCT: ifast ENT: huff + ./djpeg -dct int -nosmooth -rgb565 -bmp -outfile testout_422m_ifast_565D.bmp testout_422_ifast_opt.jpg + md5/md5cmp $(MD5_BMP_422M_IFAST_565D) testout_422m_ifast_565D.bmp + rm testout_422m_ifast_565D.bmp testout_422_ifast_opt.jpg # CC: RGB->YCC SAMP: fullsize/h2v2 FDCT: ifast ENT: prog huff - ./cjpeg -sample 2x2 -dct fast -quality 100 -prog -outfile testout_420_q100_ifast_prog.jpg $(srcdir)/testimages/testorig.ppm + ./cjpeg -sample 2x2 -quality 100 -dct fast -prog -outfile testout_420_q100_ifast_prog.jpg $(srcdir)/testimages/testorig.ppm md5/md5cmp $(MD5_JPEG_420_IFAST_Q100_PROG) testout_420_q100_ifast_prog.jpg # CC: YCC->RGB SAMP: fullsize/h2v2 fancy IDCT: ifast ENT: prog huff ./djpeg -dct fast -outfile testout_420_q100_ifast.ppm testout_420_q100_ifast_prog.jpg md5/md5cmp $(MD5_PPM_420_Q100_IFAST) testout_420_q100_ifast.ppm rm testout_420_q100_ifast.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: ifast ENT: prog huff - ./djpeg -nosmooth -dct fast -outfile testout_420m_q100_ifast.ppm testout_420_q100_ifast_prog.jpg + ./djpeg -dct fast -nosmooth -outfile testout_420m_q100_ifast.ppm testout_420_q100_ifast_prog.jpg md5/md5cmp $(MD5_PPM_420M_Q100_IFAST) testout_420m_q100_ifast.ppm rm testout_420m_q100_ifast.ppm testout_420_q100_ifast_prog.jpg # CC: RGB->Gray SAMP: fullsize FDCT: islow ENT: huff ./cjpeg -gray -dct int -outfile testout_gray_islow.jpg $(srcdir)/testimages/testorig.ppm md5/md5cmp $(MD5_JPEG_GRAY_ISLOW) testout_gray_islow.jpg -# CC: Gray->Gray SAMP: fullsize FDCT: islow ENT: huff +# CC: Gray->Gray SAMP: fullsize IDCT: islow ENT: huff ./djpeg -dct int -outfile testout_gray_islow.ppm testout_gray_islow.jpg md5/md5cmp $(MD5_PPM_GRAY_ISLOW) testout_gray_islow.ppm rm testout_gray_islow.ppm -# CC: Gray->RGB SAMP: fullsize FDCT: islow ENT: huff - ./djpeg -rgb -dct int -outfile testout_gray_rgb_islow.ppm testout_gray_islow.jpg - md5/md5cmp $(MD5_PPM_GRAY_RGB_ISLOW) testout_gray_rgb_islow.ppm - rm testout_gray_rgb_islow.ppm testout_gray_islow.jpg +# CC: Gray->RGB SAMP: fullsize IDCT: islow ENT: huff + ./djpeg -dct int -rgb -outfile testout_gray_islow_rgb.ppm testout_gray_islow.jpg + md5/md5cmp $(MD5_PPM_GRAY_ISLOW_RGB) testout_gray_islow_rgb.ppm + rm testout_gray_islow_rgb.ppm +# CC: Gray->RGB565 SAMP: fullsize IDCT: islow ENT: huff + ./djpeg -dct int -rgb565 -dither none -bmp -outfile testout_gray_islow_565.bmp testout_gray_islow.jpg + md5/md5cmp $(MD5_BMP_GRAY_ISLOW_565) testout_gray_islow_565.bmp + rm testout_gray_islow_565.bmp +# CC: Gray->RGB565 (dithered) SAMP: fullsize IDCT: islow ENT: huff + ./djpeg -dct int -rgb565 -bmp -outfile testout_gray_islow_565D.bmp testout_gray_islow.jpg + md5/md5cmp $(MD5_BMP_GRAY_ISLOW_565D) testout_gray_islow_565D.bmp + rm testout_gray_islow_565D.bmp testout_gray_islow.jpg # CC: RGB->YCC SAMP: fullsize smooth/h2v2 smooth FDCT: islow # ENT: 2-pass huff @@ -291,7 +325,7 @@ if WITH_ARITH_ENC md5/md5cmp $(MD5_JPEG_420_ISLOW_ARI) testout_420_islow_ari.jpg rm testout_420_islow_ari.jpg # CC: YCC->RGB SAMP: fullsize FDCT: islow ENT: prog arith - ./cjpeg -dct int -progressive -arithmetic -sample 1x1 -outfile testout_444_islow_progari.jpg $(srcdir)/testimages/testorig.ppm + ./cjpeg -sample 1x1 -dct int -progressive -arithmetic -outfile testout_444_islow_progari.jpg $(srcdir)/testimages/testorig.ppm md5/md5cmp $(MD5_JPEG_444_ISLOW_PROGARI) testout_444_islow_progari.jpg rm testout_444_islow_progari.jpg endif @@ -306,57 +340,73 @@ if WITH_ARITH_DEC endif # CC: YCC->RGB SAMP: h2v2 merged IDCT: 16x16 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 2/1 -ppm -outfile testout_420m_islow_2_1.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 2/1 -nosmooth -ppm -outfile testout_420m_islow_2_1.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_2_1) testout_420m_islow_2_1.ppm rm testout_420m_islow_2_1.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 15x15 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 15/8 -ppm -outfile testout_420m_islow_15_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 15/8 -nosmooth -ppm -outfile testout_420m_islow_15_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_15_8) testout_420m_islow_15_8.ppm rm testout_420m_islow_15_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 13x13 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 13/8 -ppm -outfile testout_420m_islow_13_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 13/8 -nosmooth -ppm -outfile testout_420m_islow_13_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_13_8) testout_420m_islow_13_8.ppm rm testout_420m_islow_13_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 11x11 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 11/8 -ppm -outfile testout_420m_islow_11_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 11/8 -nosmooth -ppm -outfile testout_420m_islow_11_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_11_8) testout_420m_islow_11_8.ppm rm testout_420m_islow_11_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 9x9 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 9/8 -ppm -outfile testout_420m_islow_9_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 9/8 -nosmooth -ppm -outfile testout_420m_islow_9_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_9_8) testout_420m_islow_9_8.ppm rm testout_420m_islow_9_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 7x7 islow/14x14 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 7/8 -ppm -outfile testout_420m_islow_7_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 7/8 -nosmooth -ppm -outfile testout_420m_islow_7_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_7_8) testout_420m_islow_7_8.ppm rm testout_420m_islow_7_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 6x6 islow/12x12 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 3/4 -ppm -outfile testout_420m_islow_3_4.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 3/4 -nosmooth -ppm -outfile testout_420m_islow_3_4.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_3_4) testout_420m_islow_3_4.ppm rm testout_420m_islow_3_4.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 5x5 islow/10x10 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 5/8 -ppm -outfile testout_420m_islow_5_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 5/8 -nosmooth -ppm -outfile testout_420m_islow_5_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_5_8) testout_420m_islow_5_8.ppm rm testout_420m_islow_5_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 4x4 islow/8x8 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 1/2 -ppm -outfile testout_420m_islow_1_2.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 1/2 -nosmooth -ppm -outfile testout_420m_islow_1_2.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_1_2) testout_420m_islow_1_2.ppm rm testout_420m_islow_1_2.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 3x3 islow/6x6 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 3/8 -ppm -outfile testout_420m_islow_3_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 3/8 -nosmooth -ppm -outfile testout_420m_islow_3_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_3_8) testout_420m_islow_3_8.ppm rm testout_420m_islow_3_8.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 2x2 islow/4x4 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 1/4 -ppm -outfile testout_420m_islow_1_4.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 1/4 -nosmooth -ppm -outfile testout_420m_islow_1_4.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_1_4) testout_420m_islow_1_4.ppm rm testout_420m_islow_1_4.ppm # CC: YCC->RGB SAMP: h2v2 merged IDCT: 1x1 islow/2x2 islow ENT: huff - ./djpeg -dct int -nosmooth -scale 1/8 -ppm -outfile testout_420m_islow_1_8.ppm $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -scale 1/8 -nosmooth -ppm -outfile testout_420m_islow_1_8.ppm $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_PPM_420M_ISLOW_1_8) testout_420m_islow_1_8.ppm rm testout_420m_islow_1_8.ppm # CC: YCC->RGB (dithered) SAMP: h2v2 fancy IDCT: islow ENT: huff - ./djpeg -dct int -bmp -colors 256 -outfile testout_420_islow_256.bmp $(srcdir)/testimages/testorig.jpg + ./djpeg -dct int -colors 256 -bmp -outfile testout_420_islow_256.bmp $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_BMP_420_ISLOW_256) testout_420_islow_256.bmp rm testout_420_islow_256.bmp +# CC: YCC->RGB565 SAMP: h2v2 fancy IDCT: islow ENT: huff + ./djpeg -dct int -rgb565 -dither none -bmp -outfile testout_420_islow_565.bmp $(srcdir)/testimages/testorig.jpg + md5/md5cmp $(MD5_BMP_420_ISLOW_565) testout_420_islow_565.bmp + rm testout_420_islow_565.bmp +# CC: YCC->RGB565 (dithered) SAMP: h2v2 fancy IDCT: islow ENT: huff + ./djpeg -dct int -rgb565 -bmp -outfile testout_420_islow_565D.bmp $(srcdir)/testimages/testorig.jpg + md5/md5cmp $(MD5_BMP_420_ISLOW_565D) testout_420_islow_565D.bmp + rm testout_420_islow_565D.bmp +# CC: YCC->RGB565 SAMP: h2v2 merged IDCT: islow ENT: huff + ./djpeg -dct int -nosmooth -rgb565 -dither none -bmp -outfile testout_420m_islow_565.bmp $(srcdir)/testimages/testorig.jpg + md5/md5cmp $(MD5_BMP_420M_ISLOW_565) testout_420m_islow_565.bmp + rm testout_420m_islow_565.bmp +# CC: YCC->RGB565 (dithered) SAMP: h2v2 merged IDCT: islow ENT: huff + ./djpeg -dct int -nosmooth -rgb565 -bmp -outfile testout_420m_islow_565D.bmp $(srcdir)/testimages/testorig.jpg + md5/md5cmp $(MD5_BMP_420M_ISLOW_565D) testout_420m_islow_565D.bmp + rm testout_420m_islow_565D.bmp ./jpegtran -crop 120x90+20+50 -transpose -perfect -outfile testout_crop.jpg $(srcdir)/testimages/testorig.jpg md5/md5cmp $(MD5_JPEG_CROP) testout_crop.jpg diff --git a/djpeg.c b/djpeg.c index 7a2eaa0..9b95e3c 100644 --- a/djpeg.c +++ b/djpeg.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010-2011, 2013, D. R. Commander. + * Copyright (C) 2010-2011, 2013-2014, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains a command-line user interface for the JPEG decompressor. @@ -107,6 +107,7 @@ usage (void) fprintf(stderr, " -fast Fast, low-quality processing\n"); fprintf(stderr, " -grayscale Force grayscale output\n"); fprintf(stderr, " -rgb Force RGB output\n"); + fprintf(stderr, " -rgb565 Force RGB565 output\n"); #ifdef IDCT_SCALING_SUPPORTED fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n"); #endif @@ -281,6 +282,10 @@ parse_switches (j_decompress_ptr cinfo, int argc, char **argv, /* Force RGB output. */ cinfo->out_color_space = JCS_RGB; + } else if (keymatch(arg, "rgb565", 2)) { + /* Force RGB565 output. */ + cinfo->out_color_space = JCS_RGB565; + } else if (keymatch(arg, "map", 3)) { /* Quantize to a color map taken from an input file. */ if (++argn >= argc) /* advance to next argument */ diff --git a/jdcol565.c b/jdcol565.c new file mode 100644 index 0000000..a2c98f3 --- /dev/null +++ b/jdcol565.c @@ -0,0 +1,408 @@ +/* + * jdcol565.c + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modifications: + * Copyright (C) 2013, Linaro Limited. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +/* This file is included by jdcolor.c */ + + +#define PACK_SHORT_565(r, g, b) ((((r) << 8) & 0xf800) | \ + (((g) << 3) & 0x7E0) | ((b) >> 3)) +#define PACK_TWO_PIXELS(l, r) ((r << 16) | l) +#define PACK_NEED_ALIGNMENT(ptr) (((size_t)(ptr)) & 3) + +#define WRITE_TWO_PIXELS(addr, pixels) { \ + ((INT16*)(addr))[0] = (pixels); \ + ((INT16*)(addr))[1] = (pixels) >> 16; \ +} +#define WRITE_TWO_ALIGNED_PIXELS(addr, pixels) ((*(INT32 *)(addr)) = pixels) + +#define DITHER_565_R(r, dither) ((r) + ((dither) & 0xFF)) +#define DITHER_565_G(g, dither) ((g) + (((dither) & 0xFF) >> 1)) +#define DITHER_565_B(b, dither) ((b) + ((dither) & 0xFF)) + + +/* Declarations for ordered dithering + * + * We use a 4x4 ordered dither array packed into 32 bits. This array is + * sufficent for dithering RGB888 to RGB565. + */ + +#define DITHER_MASK 0x3 +#define DITHER_ROTATE(x) (((x) << 24) | (((x) >> 8) & 0x00FFFFFF)) +static const INT32 dither_matrix[4] = { + 0x0008020A, + 0x0C040E06, + 0x030B0109, + 0x0F070D05 +}; + + +METHODDEF(void) +ycc_rgb565_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + INT32 rgb; + unsigned int r, g, b; + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + + if (PACK_NEED_ALIGNMENT(outptr)) { + y = GETJSAMPLE(*inptr0++); + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + r = range_limit[y + Crrtab[cr]]; + g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + b = range_limit[y + Cbbtab[cb]]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + outptr += 2; + num_cols--; + } + for (col = 0; col < (num_cols >> 1); col++) { + y = GETJSAMPLE(*inptr0++); + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + r = range_limit[y + Crrtab[cr]]; + g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + b = range_limit[y + Cbbtab[cb]]; + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr0++); + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + r = range_limit[y + Crrtab[cr]]; + g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + b = range_limit[y + Cbbtab[cb]]; + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_ALIGNED_PIXELS(outptr, rgb); + outptr += 4; + } + if (num_cols & 1) { + y = GETJSAMPLE(*inptr0); + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + r = range_limit[y + Crrtab[cr]]; + g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + b = range_limit[y + Cbbtab[cb]]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + } + } +} + + +METHODDEF(void) +ycc_rgb565D_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK]; + SHIFT_TEMPS + + while (--num_rows >= 0) { + INT32 rgb; + unsigned int r, g, b; + + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + if (PACK_NEED_ALIGNMENT(outptr)) { + y = GETJSAMPLE(*inptr0++); + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)]; + g = range_limit[DITHER_565_G(y + + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)), d0)]; + b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + outptr += 2; + num_cols--; + } + for (col = 0; col < (num_cols >> 1); col++) { + y = GETJSAMPLE(*inptr0++); + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)]; + g = range_limit[DITHER_565_G(y + + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)), d0)]; + b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr0++); + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)]; + g = range_limit[DITHER_565_G(y + + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)), d0)]; + b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_ALIGNED_PIXELS(outptr, rgb); + outptr += 4; + } + if (num_cols & 1) { + y = GETJSAMPLE(*inptr0); + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)]; + g = range_limit[DITHER_565_G(y + + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)), d0)]; + b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + } + } +} + + +METHODDEF(void) +rgb_rgb565_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + SHIFT_TEMPS + + while (--num_rows >= 0) { + INT32 rgb; + unsigned int r, g, b; + + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + if (PACK_NEED_ALIGNMENT(outptr)) { + r = GETJSAMPLE(*inptr0++); + g = GETJSAMPLE(*inptr1++); + b = GETJSAMPLE(*inptr2++); + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + outptr += 2; + num_cols--; + } + for (col = 0; col < (num_cols >> 1); col++) { + r = GETJSAMPLE(*inptr0++); + g = GETJSAMPLE(*inptr1++); + b = GETJSAMPLE(*inptr2++); + rgb = PACK_SHORT_565(r, g, b); + + r = GETJSAMPLE(*inptr0++); + g = GETJSAMPLE(*inptr1++); + b = GETJSAMPLE(*inptr2++); + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_ALIGNED_PIXELS(outptr, rgb); + outptr += 4; + } + if (num_cols & 1) { + r = GETJSAMPLE(*inptr0); + g = GETJSAMPLE(*inptr1); + b = GETJSAMPLE(*inptr2); + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + } + } +} + + +METHODDEF(void) +rgb_rgb565D_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + register JSAMPLE * range_limit = cinfo->sample_range_limit; + JDIMENSION num_cols = cinfo->output_width; + INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK]; + SHIFT_TEMPS + + while (--num_rows >= 0) { + INT32 rgb; + unsigned int r, g, b; + + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + if (PACK_NEED_ALIGNMENT(outptr)) { + r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)]; + g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)]; + b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + outptr += 2; + num_cols--; + } + for (col = 0; col < (num_cols >> 1); col++) { + r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)]; + g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)]; + b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_SHORT_565(r, g, b); + + r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)]; + g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)]; + b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_ALIGNED_PIXELS(outptr, rgb); + outptr += 4; + } + if (num_cols & 1) { + r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0), d0)]; + g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1), d0)]; + b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2), d0)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + } + } +} + + +METHODDEF(void) +gray_rgb565_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + INT32 rgb; + unsigned int g; + + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + if (PACK_NEED_ALIGNMENT(outptr)) { + g = *inptr++; + rgb = PACK_SHORT_565(g, g, g); + *(INT16*)outptr = rgb; + outptr += 2; + num_cols--; + } + for (col = 0; col < (num_cols >> 1); col++) { + g = *inptr++; + rgb = PACK_SHORT_565(g, g, g); + g = *inptr++; + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(g, g, g)); + WRITE_TWO_ALIGNED_PIXELS(outptr, rgb); + outptr += 4; + } + if (num_cols & 1) { + g = *inptr; + rgb = PACK_SHORT_565(g, g, g); + *(INT16*)outptr = rgb; + } + } +} + + +METHODDEF(void) +gray_rgb565D_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + register JSAMPLE * range_limit = cinfo->sample_range_limit; + JDIMENSION num_cols = cinfo->output_width; + INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK]; + + while (--num_rows >= 0) { + INT32 rgb; + unsigned int g; + + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + if (PACK_NEED_ALIGNMENT(outptr)) { + g = *inptr++; + g = range_limit[DITHER_565_R(g, d0)]; + rgb = PACK_SHORT_565(g, g, g); + *(INT16*)outptr = rgb; + outptr += 2; + num_cols--; + } + for (col = 0; col < (num_cols >> 1); col++) { + g = *inptr++; + g = range_limit[DITHER_565_R(g, d0)]; + rgb = PACK_SHORT_565(g, g, g); + d0 = DITHER_ROTATE(d0); + + g = *inptr++; + g = range_limit[DITHER_565_R(g, d0)]; + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(g, g, g)); + d0 = DITHER_ROTATE(d0); + + WRITE_TWO_ALIGNED_PIXELS(outptr, rgb); + outptr += 4; + } + if (num_cols & 1) { + g = *inptr; + g = range_limit[DITHER_565_R(g, d0)]; + rgb = PACK_SHORT_565(g, g, g); + *(INT16*)outptr = rgb; + } + } +} diff --git a/jdcolor.c b/jdcolor.c index 8dae08d..932c253 100644 --- a/jdcolor.c +++ b/jdcolor.c @@ -7,6 +7,7 @@ * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB * Copyright (C) 2009, 2011-2012, D. R. Commander. + * Copyright (C) 2013, Linaro Limited. * For conditions of distribution and use, see the accompanying README file. * * This file contains output colorspace conversion routines. @@ -543,6 +544,9 @@ ycck_cmyk_convert (j_decompress_ptr cinfo, } +#include "jdcol565.c" + + /* * Empty method for start_pass. */ @@ -649,6 +653,32 @@ jinit_color_deconverter (j_decompress_ptr cinfo) ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); break; + case JCS_RGB565: + cinfo->out_color_components = 3; + if (cinfo->dither_mode == JDITHER_NONE) { + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb565_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb565_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB) { + cconvert->pub.color_convert = rgb_rgb565_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } else { + /* only ordered dithering is supported */ + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb565D_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb565D_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB) { + cconvert->pub.color_convert = rgb_rgb565D_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + } + break; + case JCS_CMYK: cinfo->out_color_components = 4; if (cinfo->jpeg_color_space == JCS_YCCK) { diff --git a/jdmaster.c b/jdmaster.c index b9f78fd..30be6cf 100644 --- a/jdmaster.c +++ b/jdmaster.c @@ -6,6 +6,8 @@ * Modified 2002-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright (C) 2009-2011, D. R. Commander. + * Copyright (C) 2013, Linaro Limited. + * For conditions of distribution and use, see the accompanying README file. * * This file contains master control logic for the JPEG decompressor. @@ -51,9 +53,10 @@ use_merged_upsample (j_decompress_ptr cinfo) /* Merging is the equivalent of plain box-filter upsampling */ if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) return FALSE; - /* jdmerge.c only supports YCC=>RGB color conversion */ + /* jdmerge.c only supports YCC=>RGB and YCC=>RGB565 color conversion */ if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || (cinfo->out_color_space != JCS_RGB && + cinfo->out_color_space != JCS_RGB565 && cinfo->out_color_space != JCS_EXT_RGB && cinfo->out_color_space != JCS_EXT_RGBX && cinfo->out_color_space != JCS_EXT_BGR && @@ -63,8 +66,12 @@ use_merged_upsample (j_decompress_ptr cinfo) cinfo->out_color_space != JCS_EXT_RGBA && cinfo->out_color_space != JCS_EXT_BGRA && cinfo->out_color_space != JCS_EXT_ABGR && - cinfo->out_color_space != JCS_EXT_ARGB) || - cinfo->out_color_components != rgb_pixelsize[cinfo->out_color_space]) + cinfo->out_color_space != JCS_EXT_ARGB)) + return FALSE; + if ((cinfo->out_color_space == JCS_RGB565 && + cinfo->out_color_components != 3) || + (cinfo->out_color_space != JCS_RGB565 && + cinfo->out_color_components != rgb_pixelsize[cinfo->out_color_space])) return FALSE; /* and it only handles 2h1v or 2h2v sampling ratios */ if (cinfo->comp_info[0].h_samp_factor != 2 || @@ -352,6 +359,7 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo) cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space]; break; case JCS_YCbCr: + case JCS_RGB565: cinfo->out_color_components = 3; break; case JCS_CMYK: diff --git a/jdmerge.c b/jdmerge.c index c669b17..b82fe47 100644 --- a/jdmerge.c +++ b/jdmerge.c @@ -6,6 +6,7 @@ * Copyright 2009 Pierre Ossman for Cendio AB * libjpeg-turbo Modifications: * Copyright (C) 2009, 2011, D. R. Commander. + * Copyright (C) 2013, Linaro Limited. * For conditions of distribution and use, see the accompanying README file. * * This file contains code for merged upsampling/color conversion. @@ -44,6 +45,38 @@ #ifdef UPSAMPLE_MERGING_SUPPORTED +#define PACK_SHORT_565(r, g, b) ((((r) << 8) & 0xf800) | \ + (((g) << 3) & 0x7E0) | ((b) >> 3)) +#define PACK_TWO_PIXELS(l, r) ((r << 16) | l) +#define PACK_NEED_ALIGNMENT(ptr) (((size_t)(ptr)) & 3) + +#define WRITE_TWO_PIXELS(addr, pixels) { \ + ((INT16*)(addr))[0] = (pixels); \ + ((INT16*)(addr))[1] = (pixels) >> 16; \ +} +#define WRITE_TWO_ALIGNED_PIXELS(addr, pixels) ((*(INT32 *)(addr)) = pixels) + +#define DITHER_565_R(r, dither) ((r) + ((dither) & 0xFF)) +#define DITHER_565_G(g, dither) ((g) + (((dither) & 0xFF) >> 1)) +#define DITHER_565_B(b, dither) ((b) + ((dither) & 0xFF)) + + +/* Declarations for ordered dithering + * + * We use a 4x4 ordered dither array packed into 32 bits. This array is + * sufficent for dithering RGB888 to RGB565. + */ + +#define DITHER_MASK 0x3 +#define DITHER_ROTATE(x) (((x) << 24) | (((x) >> 8) & 0x00FFFFFF)) +static const INT32 dither_matrix[4] = { + 0x0008020A, + 0x0C040E06, + 0x030B0109, + 0x0F070D05 +}; + + /* Private subobject */ typedef struct { @@ -260,8 +293,11 @@ merged_2v_upsample (j_decompress_ptr cinfo, if (upsample->spare_full) { /* If we have a spare row saved from a previous cycle, just return it. */ + JDIMENSION size = upsample->out_row_width; + if (cinfo->out_color_space == JCS_RGB565) + size = cinfo->output_width * 2; jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, - 1, upsample->out_row_width); + 1, size); num_rows = 1; upsample->spare_full = FALSE; } else { @@ -416,6 +452,341 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, } +METHODDEF(void) +h2v1_merged_upsample_565 (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + unsigned int r, g, b; + INT32 rgb; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr0++); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_PIXELS(outptr, rgb); + outptr += 4; + } + + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + } + } + + +METHODDEF(void) +h2v1_merged_upsample_565D (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK]; + unsigned int r, g, b; + INT32 rgb; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + r = range_limit[DITHER_565_R(y + cred, d0)]; + g = range_limit[DITHER_565_G(y + cgreen, d0)]; + b = range_limit[DITHER_565_B(y + cblue, d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr0++); + r = range_limit[DITHER_565_R(y + cred, d0)]; + g = range_limit[DITHER_565_G(y + cgreen, d0)]; + b = range_limit[DITHER_565_B(y + cblue, d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_PIXELS(outptr, rgb); + outptr += 4; + } + + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + r = range_limit[DITHER_565_R(y + cred, d0)]; + g = range_limit[DITHER_565_G(y + cgreen, d0)]; + b = range_limit[DITHER_565_B(y + cblue, d0)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr = rgb; + } +} + + +METHODDEF(void) +h2v2_merged_upsample_565 (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + unsigned int r, g, b; + INT32 rgb; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr * 2]; + inptr01 = input_buf[0][in_row_group_ctr * 2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr00++); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_PIXELS(outptr0, rgb); + outptr0 += 4; + + y = GETJSAMPLE(*inptr01++); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr01++); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_PIXELS(outptr1, rgb); + outptr1 += 4; + } + + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + + y = GETJSAMPLE(*inptr00); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr0 = rgb; + + y = GETJSAMPLE(*inptr01); + r = range_limit[y + cred]; + g = range_limit[y + cgreen]; + b = range_limit[y + cblue]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr1 = rgb; + } +} + + +METHODDEF(void) +h2v2_merged_upsample_565D (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK]; + INT32 d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK]; + unsigned int r, g, b; + INT32 rgb; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + r = range_limit[DITHER_565_R(y + cred, d0)]; + g = range_limit[DITHER_565_G(y + cgreen, d0)]; + b = range_limit[DITHER_565_B(y + cblue, d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr00++); + r = range_limit[DITHER_565_R(y + cred, d1)]; + g = range_limit[DITHER_565_G(y + cgreen, d1)]; + b = range_limit[DITHER_565_B(y + cblue, d1)]; + d1 = DITHER_ROTATE(d1); + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_PIXELS(outptr0, rgb); + outptr0 += 4; + + y = GETJSAMPLE(*inptr01++); + r = range_limit[DITHER_565_R(y + cred, d0)]; + g = range_limit[DITHER_565_G(y + cgreen, d0)]; + b = range_limit[DITHER_565_B(y + cblue, d0)]; + d0 = DITHER_ROTATE(d0); + rgb = PACK_SHORT_565(r, g, b); + + y = GETJSAMPLE(*inptr01++); + r = range_limit[DITHER_565_R(y + cred, d1)]; + g = range_limit[DITHER_565_G(y + cgreen, d1)]; + b = range_limit[DITHER_565_B(y + cblue, d1)]; + d1 = DITHER_ROTATE(d1); + rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b)); + + WRITE_TWO_PIXELS(outptr1, rgb); + outptr1 += 4; + } + + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + + y = GETJSAMPLE(*inptr00); + r = range_limit[DITHER_565_R(y + cred, d0)]; + g = range_limit[DITHER_565_G(y + cgreen, d0)]; + b = range_limit[DITHER_565_B(y + cblue, d0)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr0 = rgb; + + y = GETJSAMPLE(*inptr01); + r = range_limit[DITHER_565_R(y + cred, d1)]; + g = range_limit[DITHER_565_G(y + cgreen, d1)]; + b = range_limit[DITHER_565_B(y + cblue, d1)]; + rgb = PACK_SHORT_565(r, g, b); + *(INT16*)outptr1 = rgb; + } +} + + /* * Module initialization routine for merged upsampling/color conversion. * @@ -444,6 +815,13 @@ jinit_merged_upsampler (j_decompress_ptr cinfo) upsample->upmethod = jsimd_h2v2_merged_upsample; else upsample->upmethod = h2v2_merged_upsample; + if (cinfo->out_color_space == JCS_RGB565) { + if (cinfo->dither_mode != JDITHER_NONE) { + upsample->upmethod = h2v2_merged_upsample_565D; + } else { + upsample->upmethod = h2v2_merged_upsample_565; + } + } /* Allocate a spare row buffer */ upsample->spare_row = (JSAMPROW) (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, @@ -454,6 +832,13 @@ jinit_merged_upsampler (j_decompress_ptr cinfo) upsample->upmethod = jsimd_h2v1_merged_upsample; else upsample->upmethod = h2v1_merged_upsample; + if (cinfo->out_color_space == JCS_RGB565) { + if (cinfo->dither_mode != JDITHER_NONE) { + upsample->upmethod = h2v1_merged_upsample_565D; + } else { + upsample->upmethod = h2v1_merged_upsample_565; + } + } /* No spare row needed */ upsample->spare_row = NULL; } diff --git a/jmorecfg.h b/jmorecfg.h index f41eccf..71ecb75 100644 --- a/jmorecfg.h +++ b/jmorecfg.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * Modifications: - * Copyright (C) 2009, 2011, D. R. Commander. + * Copyright (C) 2009, 2011, 2014, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains additional configuration options that customize the @@ -317,7 +317,7 @@ typedef int boolean; #define RGB_BLUE 2 /* Offset of Blue */ #define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ -#define JPEG_NUMCS 16 +#define JPEG_NUMCS 17 #define EXT_RGB_RED 0 #define EXT_RGB_GREEN 1 @@ -352,25 +352,29 @@ typedef int boolean; static const int rgb_red[JPEG_NUMCS] = { -1, -1, RGB_RED, -1, -1, -1, EXT_RGB_RED, EXT_RGBX_RED, EXT_BGR_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED, - EXT_RGBX_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED + EXT_RGBX_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED, + -1 }; static const int rgb_green[JPEG_NUMCS] = { -1, -1, RGB_GREEN, -1, -1, -1, EXT_RGB_GREEN, EXT_RGBX_GREEN, EXT_BGR_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN, - EXT_RGBX_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN + EXT_RGBX_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN, + -1 }; static const int rgb_blue[JPEG_NUMCS] = { -1, -1, RGB_BLUE, -1, -1, -1, EXT_RGB_BLUE, EXT_RGBX_BLUE, EXT_BGR_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE, - EXT_RGBX_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE + EXT_RGBX_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE, + -1 }; static const int rgb_pixelsize[JPEG_NUMCS] = { -1, -1, RGB_PIXELSIZE, -1, -1, -1, EXT_RGB_PIXELSIZE, EXT_RGBX_PIXELSIZE, EXT_BGR_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE, - EXT_RGBX_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE + EXT_RGBX_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE, + -1 }; /* Definitions for speed-related optimizations. */ diff --git a/jpeglib.h b/jpeglib.h index 55c6abc..ee757b9 100644 --- a/jpeglib.h +++ b/jpeglib.h @@ -5,7 +5,7 @@ * Copyright (C) 1991-1998, Thomas G. Lane. * Modified 2002-2009 by Guido Vollbeding. * Modifications: - * Copyright (C) 2009-2011, 2013, D. R. Commander. + * Copyright (C) 2009-2011, 2013-2014, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file defines the application interface for the JPEG library. @@ -237,7 +237,8 @@ typedef enum { JCS_EXT_RGBA, /* red/green/blue/alpha */ JCS_EXT_BGRA, /* blue/green/red/alpha */ JCS_EXT_ABGR, /* alpha/blue/green/red */ - JCS_EXT_ARGB /* alpha/red/green/blue */ + JCS_EXT_ARGB, /* alpha/red/green/blue */ + JCS_RGB565 /* 5-bit red/6-bit green/5-bit blue */ } J_COLOR_SPACE; /* DCT/IDCT algorithm options. */ diff --git a/wrbmp.c b/wrbmp.c index b8e213b..d769404 100644 --- a/wrbmp.c +++ b/wrbmp.c @@ -1,8 +1,10 @@ /* * wrbmp.c * + * This file was part of the Independent JPEG Group's software. * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. + * Modifications: + * Copyright (C) 2013, Linaro Limited. * For conditions of distribution and use, see the accompanying README file. * * This file contains routines to write output images in Microsoft "BMP" @@ -89,11 +91,30 @@ put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, */ inptr = dest->pub.buffer[0]; outptr = image_ptr[0]; - for (col = cinfo->output_width; col > 0; col--) { - outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ - outptr[1] = *inptr++; - outptr[0] = *inptr++; - outptr += 3; + + if(cinfo->out_color_space == JCS_RGB565) { + #define red_mask 0xF800 + #define green_mask 0x7E0 + #define blue_mask 0x1F + unsigned char r, g, b; + unsigned short *inptr2 = (unsigned short *)inptr; + for (col = cinfo->output_width; col > 0; col--) { + r = (*inptr2 & red_mask) >> 11; + g = (*inptr2 & green_mask) >> 5; + b = (*inptr2 & blue_mask); + outptr[0] = b << 3; + outptr[1] = g << 2; + outptr[2] = r << 3; + outptr += 3; + inptr2++; + } + } else { + for (col = cinfo->output_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } } /* Zero out the pad bytes. */ @@ -181,6 +202,9 @@ write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) bits_per_pixel = 24; cmap_entries = 0; } + } else if (cinfo->out_color_space == JCS_RGB565) { + bits_per_pixel = 24; + cmap_entries = 0; } else { /* Grayscale output. We need to fake a 256-entry colormap. */ bits_per_pixel = 8; @@ -246,6 +270,9 @@ write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) bits_per_pixel = 24; cmap_entries = 0; } + } else if (cinfo->out_color_space == JCS_RGB565) { + bits_per_pixel = 24; + cmap_entries = 0; } else { /* Grayscale output. We need to fake a 256-entry colormap. */ bits_per_pixel = 8; @@ -407,6 +434,8 @@ jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2) dest->pub.put_pixel_rows = put_gray_rows; else dest->pub.put_pixel_rows = put_pixel_rows; + } else if(cinfo->out_color_space == JCS_RGB565 ) { + dest->pub.put_pixel_rows = put_pixel_rows; } else { ERREXIT(cinfo, JERR_BMP_COLORSPACE); } @@ -415,16 +444,26 @@ jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2) jpeg_calc_output_dimensions(cinfo); /* Determine width of rows in the BMP file (padded to 4-byte boundary). */ - row_width = cinfo->output_width * cinfo->output_components; - dest->data_width = row_width; - while ((row_width & 3) != 0) row_width++; - dest->row_width = row_width; - dest->pad_bytes = (int) (row_width - dest->data_width); + if (cinfo->out_color_space == JCS_RGB565) { + row_width = cinfo->output_width * 2; + dest->row_width = dest->data_width = cinfo->output_width * 3; + } else { + row_width = cinfo->output_width * cinfo->output_components; + dest->row_width = dest->data_width = row_width; + } + while ((dest->row_width & 3) != 0) dest->row_width++; + dest->pad_bytes = (int) (dest->row_width - dest->data_width); + if (cinfo->out_color_space == JCS_RGB565) { + while ((row_width & 3) != 0) row_width++; + } else { + row_width = dest->row_width; + } + /* Allocate space for inversion array, prepare for write pass */ dest->whole_image = (*cinfo->mem->request_virt_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, - row_width, cinfo->output_height, (JDIMENSION) 1); + dest->row_width, cinfo->output_height, (JDIMENSION) 1); dest->cur_output_row = 0; if (cinfo->progress != NULL) { cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;