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 @@
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_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 @@
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 @@
-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 @@
-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 @@
${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 @@
${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 @@
-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(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 @@
# 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 @@
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 @@
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 @@
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_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 @@
# 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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 <ossman@cendio.se> 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 @@
}
+#include "jdcol565.c"
+
+
/*
* Empty method for start_pass.
*/
@@ -649,6 +653,32 @@
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 @@
/* 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 @@
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 @@
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 <ossman@cendio.se> 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 @@
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 @@
}
+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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
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 @@
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;