TJDecompressor.java 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /*
  2. * Copyright (C)2011-2015 D. R. Commander. All Rights Reserved.
  3. * Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * - Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. * - Redistributions in binary form must reproduce the above copyright notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. * - Neither the name of the libjpeg-turbo Project nor the names of its
  14. * contributors may be used to endorse or promote products derived from this
  15. * software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
  18. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
  21. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. * POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. package org.libjpegturbo.turbojpeg;
  30. import java.awt.image.*;
  31. import java.nio.*;
  32. import java.io.*;
  33. /**
  34. * TurboJPEG decompressor
  35. */
  36. public class TJDecompressor implements Closeable {
  37. private static final String NO_ASSOC_ERROR =
  38. "No JPEG image is associated with this instance";
  39. /**
  40. * Create a TurboJPEG decompresssor instance.
  41. */
  42. public TJDecompressor() throws TJException {
  43. init();
  44. }
  45. /**
  46. * Create a TurboJPEG decompressor instance and associate the JPEG source
  47. * image stored in <code>jpegImage</code> with the newly created instance.
  48. *
  49. * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
  50. * be the length of the array.) This buffer is not modified.
  51. */
  52. public TJDecompressor(byte[] jpegImage) throws TJException {
  53. init();
  54. setSourceImage(jpegImage, jpegImage.length);
  55. }
  56. /**
  57. * Create a TurboJPEG decompressor instance and associate the JPEG source
  58. * image of length <code>imageSize</code> bytes stored in
  59. * <code>jpegImage</code> with the newly created instance.
  60. *
  61. * @param jpegImage JPEG image buffer. This buffer is not modified.
  62. *
  63. * @param imageSize size of the JPEG image (in bytes)
  64. */
  65. public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
  66. init();
  67. setSourceImage(jpegImage, imageSize);
  68. }
  69. /**
  70. * Create a TurboJPEG decompressor instance and associate the YUV planar
  71. * source image stored in <code>yuvImage</code> with the newly created
  72. * instance.
  73. *
  74. * @param yuvImage {@link YUVImage} instance containing a YUV planar
  75. * image to be decoded. This image is not modified.
  76. */
  77. public TJDecompressor(YUVImage yuvImage) throws TJException {
  78. init();
  79. setSourceImage(yuvImage);
  80. }
  81. /**
  82. * Associate the JPEG image of length <code>imageSize</code> bytes stored in
  83. * <code>jpegImage</code> with this decompressor instance. This image will
  84. * be used as the source image for subsequent decompress operations.
  85. *
  86. * @param jpegImage JPEG image buffer. This buffer is not modified.
  87. *
  88. * @param imageSize size of the JPEG image (in bytes)
  89. */
  90. public void setSourceImage(byte[] jpegImage, int imageSize)
  91. throws TJException {
  92. if (jpegImage == null || imageSize < 1)
  93. throw new IllegalArgumentException("Invalid argument in setSourceImage()");
  94. jpegBuf = jpegImage;
  95. jpegBufSize = imageSize;
  96. decompressHeader(jpegBuf, jpegBufSize);
  97. yuvImage = null;
  98. }
  99. /**
  100. * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
  101. */
  102. @Deprecated
  103. public void setJPEGImage(byte[] jpegImage, int imageSize)
  104. throws TJException {
  105. setSourceImage(jpegImage, imageSize);
  106. }
  107. /**
  108. * Associate the specified YUV planar source image with this decompressor
  109. * instance. Subsequent decompress operations will decode this image into an
  110. * RGB or grayscale destination image.
  111. *
  112. * @param srcImage {@link YUVImage} instance containing a YUV planar image to
  113. * be decoded. This image is not modified.
  114. */
  115. public void setSourceImage(YUVImage srcImage) {
  116. if (srcImage == null)
  117. throw new IllegalArgumentException("Invalid argument in setSourceImage()");
  118. yuvImage = srcImage;
  119. jpegBuf = null;
  120. jpegBufSize = 0;
  121. }
  122. /**
  123. * Returns the width of the source image (JPEG or YUV) associated with this
  124. * decompressor instance.
  125. *
  126. * @return the width of the source image (JPEG or YUV) associated with this
  127. * decompressor instance.
  128. */
  129. public int getWidth() {
  130. if (yuvImage != null)
  131. return yuvImage.getWidth();
  132. if (jpegWidth < 1)
  133. throw new IllegalStateException(NO_ASSOC_ERROR);
  134. return jpegWidth;
  135. }
  136. /**
  137. * Returns the height of the source image (JPEG or YUV) associated with this
  138. * decompressor instance.
  139. *
  140. * @return the height of the source image (JPEG or YUV) associated with this
  141. * decompressor instance.
  142. */
  143. public int getHeight() {
  144. if (yuvImage != null)
  145. return yuvImage.getHeight();
  146. if (jpegHeight < 1)
  147. throw new IllegalStateException(NO_ASSOC_ERROR);
  148. return jpegHeight;
  149. }
  150. /**
  151. * Returns the level of chrominance subsampling used in the source image
  152. * (JPEG or YUV) associated with this decompressor instance. See
  153. * {@link TJ#SAMP_444 TJ.SAMP_*}.
  154. *
  155. * @return the level of chrominance subsampling used in the source image
  156. * (JPEG or YUV) associated with this decompressor instance.
  157. */
  158. public int getSubsamp() {
  159. if (yuvImage != null)
  160. return yuvImage.getSubsamp();
  161. if (jpegSubsamp < 0)
  162. throw new IllegalStateException(NO_ASSOC_ERROR);
  163. if (jpegSubsamp >= TJ.NUMSAMP)
  164. throw new IllegalStateException("JPEG header information is invalid");
  165. return jpegSubsamp;
  166. }
  167. /**
  168. * Returns the colorspace used in the source image (JPEG or YUV) associated
  169. * with this decompressor instance. See {@link TJ#CS_RGB TJ.CS_*}. If the
  170. * source image is YUV, then this always returns {@link TJ#CS_YCbCr}.
  171. *
  172. * @return the colorspace used in the source image (JPEG or YUV) associated
  173. * with this decompressor instance.
  174. */
  175. public int getColorspace() {
  176. if (yuvImage != null)
  177. return TJ.CS_YCbCr;
  178. if (jpegColorspace < 0)
  179. throw new IllegalStateException(NO_ASSOC_ERROR);
  180. if (jpegColorspace >= TJ.NUMCS)
  181. throw new IllegalStateException("JPEG header information is invalid");
  182. return jpegColorspace;
  183. }
  184. /**
  185. * Returns the JPEG image buffer associated with this decompressor instance.
  186. *
  187. * @return the JPEG image buffer associated with this decompressor instance.
  188. */
  189. public byte[] getJPEGBuf() {
  190. if (jpegBuf == null)
  191. throw new IllegalStateException(NO_ASSOC_ERROR);
  192. return jpegBuf;
  193. }
  194. /**
  195. * Returns the size of the JPEG image (in bytes) associated with this
  196. * decompressor instance.
  197. *
  198. * @return the size of the JPEG image (in bytes) associated with this
  199. * decompressor instance.
  200. */
  201. public int getJPEGSize() {
  202. if (jpegBufSize < 1)
  203. throw new IllegalStateException(NO_ASSOC_ERROR);
  204. return jpegBufSize;
  205. }
  206. /**
  207. * Returns the width of the largest scaled-down image that the TurboJPEG
  208. * decompressor can generate without exceeding the desired image width and
  209. * height.
  210. *
  211. * @param desiredWidth desired width (in pixels) of the decompressed image.
  212. * Setting this to 0 is the same as setting it to the width of the JPEG image
  213. * (in other words, the width will not be considered when determining the
  214. * scaled image size.)
  215. *
  216. * @param desiredHeight desired height (in pixels) of the decompressed image.
  217. * Setting this to 0 is the same as setting it to the height of the JPEG
  218. * image (in other words, the height will not be considered when determining
  219. * the scaled image size.)
  220. *
  221. * @return the width of the largest scaled-down image that the TurboJPEG
  222. * decompressor can generate without exceeding the desired image width and
  223. * height.
  224. */
  225. public int getScaledWidth(int desiredWidth, int desiredHeight) {
  226. if (jpegWidth < 1 || jpegHeight < 1)
  227. throw new IllegalStateException(NO_ASSOC_ERROR);
  228. if (desiredWidth < 0 || desiredHeight < 0)
  229. throw new IllegalArgumentException("Invalid argument in getScaledWidth()");
  230. TJScalingFactor[] sf = TJ.getScalingFactors();
  231. if (desiredWidth == 0)
  232. desiredWidth = jpegWidth;
  233. if (desiredHeight == 0)
  234. desiredHeight = jpegHeight;
  235. int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
  236. for (int i = 0; i < sf.length; i++) {
  237. scaledWidth = sf[i].getScaled(jpegWidth);
  238. scaledHeight = sf[i].getScaled(jpegHeight);
  239. if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
  240. break;
  241. }
  242. if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
  243. throw new IllegalArgumentException("Could not scale down to desired image dimensions");
  244. return scaledWidth;
  245. }
  246. /**
  247. * Returns the height of the largest scaled-down image that the TurboJPEG
  248. * decompressor can generate without exceeding the desired image width and
  249. * height.
  250. *
  251. * @param desiredWidth desired width (in pixels) of the decompressed image.
  252. * Setting this to 0 is the same as setting it to the width of the JPEG image
  253. * (in other words, the width will not be considered when determining the
  254. * scaled image size.)
  255. *
  256. * @param desiredHeight desired height (in pixels) of the decompressed image.
  257. * Setting this to 0 is the same as setting it to the height of the JPEG
  258. * image (in other words, the height will not be considered when determining
  259. * the scaled image size.)
  260. *
  261. * @return the height of the largest scaled-down image that the TurboJPEG
  262. * decompressor can generate without exceeding the desired image width and
  263. * height.
  264. */
  265. public int getScaledHeight(int desiredWidth, int desiredHeight) {
  266. if (jpegWidth < 1 || jpegHeight < 1)
  267. throw new IllegalStateException(NO_ASSOC_ERROR);
  268. if (desiredWidth < 0 || desiredHeight < 0)
  269. throw new IllegalArgumentException("Invalid argument in getScaledHeight()");
  270. TJScalingFactor[] sf = TJ.getScalingFactors();
  271. if (desiredWidth == 0)
  272. desiredWidth = jpegWidth;
  273. if (desiredHeight == 0)
  274. desiredHeight = jpegHeight;
  275. int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
  276. for (int i = 0; i < sf.length; i++) {
  277. scaledWidth = sf[i].getScaled(jpegWidth);
  278. scaledHeight = sf[i].getScaled(jpegHeight);
  279. if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
  280. break;
  281. }
  282. if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
  283. throw new IllegalArgumentException("Could not scale down to desired image dimensions");
  284. return scaledHeight;
  285. }
  286. /**
  287. * Decompress the JPEG source image or decode the YUV source image associated
  288. * with this decompressor instance and output a grayscale, RGB, or CMYK image
  289. * to the given destination buffer.
  290. *
  291. * @param dstBuf buffer that will receive the decompressed/decoded image.
  292. * If the source image is a JPEG image, then this buffer should normally be
  293. * <code>pitch * scaledHeight</code> bytes in size, where
  294. * <code>scaledHeight</code> can be determined by calling <code>
  295. * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
  296. * </code> with one of the scaling factors returned from {@link
  297. * TJ#getScalingFactors} or by calling {@link #getScaledHeight}. If the
  298. * source image is a YUV image, then this buffer should normally be
  299. * <code>pitch * height</code> bytes in size, where <code>height</code> is
  300. * the height of the YUV image. However, the buffer may also be larger than
  301. * the dimensions of the source image, in which case the <code>x</code>,
  302. * <code>y</code>, and <code>pitch</code> parameters can be used to specify
  303. * the region into which the source image should be decompressed/decoded.
  304. *
  305. * @param x x offset (in pixels) of the region in the destination image into
  306. * which the source image should be decompressed/decoded
  307. *
  308. * @param y y offset (in pixels) of the region in the destination image into
  309. * which the source image should be decompressed/decoded
  310. *
  311. * @param desiredWidth If the source image is a JPEG image, then this
  312. * specifies the desired width (in pixels) of the decompressed image (or
  313. * image region.) If the desired destination image dimensions are different
  314. * than the source image dimensions, then TurboJPEG will use scaling in the
  315. * JPEG decompressor to generate the largest possible image that will fit
  316. * within the desired dimensions. Setting this to 0 is the same as setting
  317. * it to the width of the JPEG image (in other words, the width will not be
  318. * considered when determining the scaled image size.) This parameter is
  319. * ignored if the source image is a YUV image.
  320. *
  321. * @param pitch bytes per line of the destination image. Normally, this
  322. * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
  323. * the destination image is unpadded, but you can use this to, for instance,
  324. * pad each line of the destination image to a 4-byte boundary or to
  325. * decompress/decode the source image into a region of a larger image. NOTE:
  326. * if the source image is a JPEG image, then <code>scaledWidth</code> can be
  327. * determined by calling <code>
  328. * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
  329. * </code> or by calling {@link #getScaledWidth}. If the source image is a
  330. * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
  331. * Setting this parameter to 0 is the equivalent of setting it to
  332. * <code>scaledWidth * TJ.pixelSize(pixelFormat)</code>.
  333. *
  334. * @param desiredHeight If the source image is a JPEG image, then this
  335. * specifies the desired height (in pixels) of the decompressed image (or
  336. * image region.) If the desired destination image dimensions are different
  337. * than the source image dimensions, then TurboJPEG will use scaling in the
  338. * JPEG decompressor to generate the largest possible image that will fit
  339. * within the desired dimensions. Setting this to 0 is the same as setting
  340. * it to the height of the JPEG image (in other words, the height will not be
  341. * considered when determining the scaled image size.) This parameter is
  342. * ignored if the source image is a YUV image.
  343. *
  344. * @param pixelFormat pixel format of the decompressed/decoded image (one of
  345. * {@link TJ#PF_RGB TJ.PF_*})
  346. *
  347. * @param flags the bitwise OR of one or more of
  348. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  349. */
  350. public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
  351. int pitch, int desiredHeight, int pixelFormat,
  352. int flags) throws TJException {
  353. if (jpegBuf == null && yuvImage == null)
  354. throw new IllegalStateException(NO_ASSOC_ERROR);
  355. if (dstBuf == null || x < 0 || y < 0 || pitch < 0 ||
  356. (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
  357. pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
  358. throw new IllegalArgumentException("Invalid argument in decompress()");
  359. if (yuvImage != null)
  360. decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
  361. yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
  362. yuvImage.getWidth(), pitch, yuvImage.getHeight(), pixelFormat,
  363. flags);
  364. else {
  365. if (x > 0 || y > 0)
  366. decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
  367. desiredHeight, pixelFormat, flags);
  368. else
  369. decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
  370. desiredHeight, pixelFormat, flags);
  371. }
  372. }
  373. /**
  374. * @deprecated Use
  375. * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
  376. */
  377. @Deprecated
  378. public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
  379. int desiredHeight, int pixelFormat, int flags)
  380. throws TJException {
  381. decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
  382. flags);
  383. }
  384. /**
  385. * Decompress the JPEG source image associated with this decompressor
  386. * instance and return a buffer containing the decompressed image.
  387. *
  388. * @param desiredWidth see
  389. * {@link #decompress(byte[], int, int, int, int, int, int, int)}
  390. * for description
  391. *
  392. * @param pitch see
  393. * {@link #decompress(byte[], int, int, int, int, int, int, int)}
  394. * for description
  395. *
  396. * @param desiredHeight see
  397. * {@link #decompress(byte[], int, int, int, int, int, int, int)}
  398. * for description
  399. *
  400. * @param pixelFormat pixel format of the decompressed image (one of
  401. * {@link TJ#PF_RGB TJ.PF_*})
  402. *
  403. * @param flags the bitwise OR of one or more of
  404. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  405. *
  406. * @return a buffer containing the decompressed image.
  407. */
  408. public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
  409. int pixelFormat, int flags) throws TJException {
  410. if (pitch < 0 ||
  411. (yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
  412. pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
  413. throw new IllegalArgumentException("Invalid argument in decompress()");
  414. int pixelSize = TJ.getPixelSize(pixelFormat);
  415. int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
  416. int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
  417. if (pitch == 0)
  418. pitch = scaledWidth * pixelSize;
  419. byte[] buf = new byte[pitch * scaledHeight];
  420. decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
  421. return buf;
  422. }
  423. /**
  424. * Decompress the JPEG source image associated with this decompressor
  425. * instance into a YUV planar image and store it in the given
  426. * <code>YUVImage</code> instance. This method performs JPEG decompression
  427. * but leaves out the color conversion step, so a planar YUV image is
  428. * generated instead of an RGB or grayscale image. This method cannot be
  429. * used to decompress JPEG source images with the CMYK or YCCK colorspace.
  430. *
  431. * @param dstImage {@link YUVImage} instance that will receive the YUV planar
  432. * image. The level of subsampling specified in this <code>YUVImage</code>
  433. * instance must match that of the JPEG image, and the width and height
  434. * specified in the <code>YUVImage</code> instance must match one of the
  435. * scaled image sizes that TurboJPEG is capable of generating from the JPEG
  436. * source image.
  437. *
  438. * @param flags the bitwise OR of one or more of
  439. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  440. */
  441. public void decompressToYUV(YUVImage dstImage, int flags)
  442. throws TJException {
  443. if (jpegBuf == null)
  444. throw new IllegalStateException(NO_ASSOC_ERROR);
  445. if (dstImage == null || flags < 0)
  446. throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
  447. int scaledWidth = getScaledWidth(dstImage.getWidth(),
  448. dstImage.getHeight());
  449. int scaledHeight = getScaledHeight(dstImage.getWidth(),
  450. dstImage.getHeight());
  451. if (scaledWidth != dstImage.getWidth() ||
  452. scaledHeight != dstImage.getHeight())
  453. throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
  454. if (jpegSubsamp != dstImage.getSubsamp())
  455. throw new IllegalArgumentException("YUVImage subsampling level does not match that of the JPEG image");
  456. decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
  457. dstImage.getOffsets(), dstImage.getWidth(),
  458. dstImage.getStrides(), dstImage.getHeight(), flags);
  459. }
  460. /**
  461. * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
  462. */
  463. @Deprecated
  464. public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
  465. YUVImage dstImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
  466. jpegSubsamp);
  467. decompressToYUV(dstImage, flags);
  468. }
  469. /**
  470. * Decompress the JPEG source image associated with this decompressor
  471. * instance into a set of Y, U (Cb), and V (Cr) image planes and return a
  472. * <code>YUVImage</code> instance containing the decompressed image planes.
  473. * This method performs JPEG decompression but leaves out the color
  474. * conversion step, so a planar YUV image is generated instead of an RGB or
  475. * grayscale image. This method cannot be used to decompress JPEG source
  476. * images with the CMYK or YCCK colorspace.
  477. *
  478. * @param desiredWidth desired width (in pixels) of the YUV image. If the
  479. * desired image dimensions are different than the dimensions of the JPEG
  480. * image being decompressed, then TurboJPEG will use scaling in the JPEG
  481. * decompressor to generate the largest possible image that will fit within
  482. * the desired dimensions. Setting this to 0 is the same as setting it to
  483. * the width of the JPEG image (in other words, the width will not be
  484. * considered when determining the scaled image size.)
  485. *
  486. * @param strides an array of integers, each specifying the number of bytes
  487. * per line in the corresponding plane of the output image. Setting the
  488. * stride for any plane to 0 is the same as setting it to the scaled
  489. * component width of the plane. If <tt>strides</tt> is NULL, then the
  490. * strides for all planes will be set to their respective scaled component
  491. * widths. You can adjust the strides in order to add an arbitrary amount of
  492. * line padding to each plane.
  493. *
  494. * @param desiredHeight desired height (in pixels) of the YUV image. If the
  495. * desired image dimensions are different than the dimensions of the JPEG
  496. * image being decompressed, then TurboJPEG will use scaling in the JPEG
  497. * decompressor to generate the largest possible image that will fit within
  498. * the desired dimensions. Setting this to 0 is the same as setting it to
  499. * the height of the JPEG image (in other words, the height will not be
  500. * considered when determining the scaled image size.)
  501. *
  502. * @param flags the bitwise OR of one or more of
  503. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  504. *
  505. * @return a YUV planar image.
  506. */
  507. public YUVImage decompressToYUV(int desiredWidth, int[] strides,
  508. int desiredHeight,
  509. int flags) throws TJException {
  510. if (flags < 0)
  511. throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
  512. if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
  513. throw new IllegalStateException(NO_ASSOC_ERROR);
  514. if (jpegSubsamp >= TJ.NUMSAMP)
  515. throw new IllegalStateException("JPEG header information is invalid");
  516. if (yuvImage != null)
  517. throw new IllegalStateException("Source image is the wrong type");
  518. int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
  519. int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
  520. YUVImage yuvImage = new YUVImage(scaledWidth, null, scaledHeight,
  521. jpegSubsamp);
  522. decompressToYUV(yuvImage, flags);
  523. return yuvImage;
  524. }
  525. /**
  526. * Decompress the JPEG source image associated with this decompressor
  527. * instance into a unified YUV planar image buffer and return a
  528. * <code>YUVImage</code> instance containing the decompressed image. This
  529. * method performs JPEG decompression but leaves out the color conversion
  530. * step, so a planar YUV image is generated instead of an RGB or grayscale
  531. * image. This method cannot be used to decompress JPEG source images with
  532. * the CMYK or YCCK colorspace.
  533. *
  534. * @param desiredWidth desired width (in pixels) of the YUV image. If the
  535. * desired image dimensions are different than the dimensions of the JPEG
  536. * image being decompressed, then TurboJPEG will use scaling in the JPEG
  537. * decompressor to generate the largest possible image that will fit within
  538. * the desired dimensions. Setting this to 0 is the same as setting it to
  539. * the width of the JPEG image (in other words, the width will not be
  540. * considered when determining the scaled image size.)
  541. *
  542. * @param pad the width of each line in each plane of the YUV image will be
  543. * padded to the nearest multiple of this number of bytes (must be a power of
  544. * 2.)
  545. *
  546. * @param desiredHeight desired height (in pixels) of the YUV image. If the
  547. * desired image dimensions are different than the dimensions of the JPEG
  548. * image being decompressed, then TurboJPEG will use scaling in the JPEG
  549. * decompressor to generate the largest possible image that will fit within
  550. * the desired dimensions. Setting this to 0 is the same as setting it to
  551. * the height of the JPEG image (in other words, the height will not be
  552. * considered when determining the scaled image size.)
  553. *
  554. * @param flags the bitwise OR of one or more of
  555. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  556. *
  557. * @return a YUV planar image.
  558. */
  559. public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
  560. int flags) throws TJException {
  561. if (flags < 0)
  562. throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
  563. if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
  564. throw new IllegalStateException(NO_ASSOC_ERROR);
  565. if (jpegSubsamp >= TJ.NUMSAMP)
  566. throw new IllegalStateException("JPEG header information is invalid");
  567. if (yuvImage != null)
  568. throw new IllegalStateException("Source image is the wrong type");
  569. int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
  570. int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
  571. YUVImage yuvImage = new YUVImage(scaledWidth, pad, scaledHeight,
  572. jpegSubsamp);
  573. decompressToYUV(yuvImage, flags);
  574. return yuvImage;
  575. }
  576. /**
  577. * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
  578. */
  579. @Deprecated
  580. public byte[] decompressToYUV(int flags) throws TJException {
  581. YUVImage dstImage = new YUVImage(jpegWidth, 4, jpegHeight, jpegSubsamp);
  582. decompressToYUV(dstImage, flags);
  583. return dstImage.getBuf();
  584. }
  585. /**
  586. * Decompress the JPEG source image or decode the YUV source image associated
  587. * with this decompressor instance and output a grayscale, RGB, or CMYK image
  588. * to the given destination buffer.
  589. *
  590. * @param dstBuf buffer that will receive the decompressed/decoded image.
  591. * If the source image is a JPEG image, then this buffer should normally be
  592. * <code>stride * scaledHeight</code> pixels in size, where
  593. * <code>scaledHeight</code> can be determined by calling <code>
  594. * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
  595. * </code> with one of the scaling factors returned from {@link
  596. * TJ#getScalingFactors} or by calling {@link #getScaledHeight}. If the
  597. * source image is a YUV image, then this buffer should normally be
  598. * <code>stride * height</code> pixels in size, where <code>height</code> is
  599. * the height of the YUV image. However, the buffer may also be larger than
  600. * the dimensions of the JPEG image, in which case the <code>x</code>,
  601. * <code>y</code>, and <code>stride</code> parameters can be used to specify
  602. * the region into which the source image should be decompressed.
  603. *
  604. * @param x x offset (in pixels) of the region in the destination image into
  605. * which the source image should be decompressed/decoded
  606. *
  607. * @param y y offset (in pixels) of the region in the destination image into
  608. * which the source image should be decompressed/decoded
  609. *
  610. * @param desiredWidth If the source image is a JPEG image, then this
  611. * specifies the desired width (in pixels) of the decompressed image (or
  612. * image region.) If the desired destination image dimensions are different
  613. * than the source image dimensions, then TurboJPEG will use scaling in the
  614. * JPEG decompressor to generate the largest possible image that will fit
  615. * within the desired dimensions. Setting this to 0 is the same as setting
  616. * it to the width of the JPEG image (in other words, the width will not be
  617. * considered when determining the scaled image size.) This parameter is
  618. * ignored if the source image is a YUV image.
  619. *
  620. * @param stride pixels per line of the destination image. Normally, this
  621. * should be set to <code>scaledWidth</code>, but you can use this to, for
  622. * instance, decompress the JPEG image into a region of a larger image.
  623. * NOTE: if the source image is a JPEG image, then <code>scaledWidth</code>
  624. * can be determined by calling <code>
  625. * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
  626. * </code> or by calling {@link #getScaledWidth}. If the source image is a
  627. * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
  628. * Setting this parameter to 0 is the equivalent of setting it to
  629. * <code>scaledWidth</code>.
  630. *
  631. * @param desiredHeight If the source image is a JPEG image, then this
  632. * specifies the desired height (in pixels) of the decompressed image (or
  633. * image region.) If the desired destination image dimensions are different
  634. * than the source image dimensions, then TurboJPEG will use scaling in the
  635. * JPEG decompressor to generate the largest possible image that will fit
  636. * within the desired dimensions. Setting this to 0 is the same as setting
  637. * it to the height of the JPEG image (in other words, the height will not be
  638. * considered when determining the scaled image size.) This parameter is
  639. * ignored if the source image is a YUV image.
  640. *
  641. * @param pixelFormat pixel format of the decompressed image (one of
  642. * {@link TJ#PF_RGB TJ.PF_*})
  643. *
  644. * @param flags the bitwise OR of one or more of
  645. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  646. */
  647. public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
  648. int stride, int desiredHeight, int pixelFormat,
  649. int flags) throws TJException {
  650. if (jpegBuf == null && yuvImage == null)
  651. throw new IllegalStateException(NO_ASSOC_ERROR);
  652. if (dstBuf == null || x < 0 || y < 0 || stride < 0 ||
  653. (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
  654. pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
  655. throw new IllegalArgumentException("Invalid argument in decompress()");
  656. if (yuvImage != null)
  657. decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
  658. yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
  659. yuvImage.getWidth(), stride, yuvImage.getHeight(), pixelFormat,
  660. flags);
  661. else
  662. decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
  663. desiredHeight, pixelFormat, flags);
  664. }
  665. /**
  666. * Decompress the JPEG source image or decode the YUV source image associated
  667. * with this decompressor instance and output a decompressed/decoded image to
  668. * the given <code>BufferedImage</code> instance.
  669. *
  670. * @param dstImage a <code>BufferedImage</code> instance that will receive
  671. * the decompressed/decoded image. If the source image is a JPEG image, then
  672. * the width and height of the <code>BufferedImage</code> instance must match
  673. * one of the scaled image sizes that TurboJPEG is capable of generating from
  674. * the JPEG image. If the source image is a YUV image, then the width and
  675. * height of the <code>BufferedImage</code> instance must match the width and
  676. * height of the YUV image.
  677. *
  678. * @param flags the bitwise OR of one or more of
  679. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  680. */
  681. public void decompress(BufferedImage dstImage, int flags)
  682. throws TJException {
  683. if (dstImage == null || flags < 0)
  684. throw new IllegalArgumentException("Invalid argument in decompress()");
  685. int desiredWidth = dstImage.getWidth();
  686. int desiredHeight = dstImage.getHeight();
  687. int scaledWidth, scaledHeight;
  688. if (yuvImage != null) {
  689. if (desiredWidth != yuvImage.getWidth() ||
  690. desiredHeight != yuvImage.getHeight())
  691. throw new IllegalArgumentException("BufferedImage dimensions do not match the dimensions of the source image.");
  692. scaledWidth = yuvImage.getWidth();
  693. scaledHeight = yuvImage.getHeight();
  694. } else {
  695. scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
  696. scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
  697. if (scaledWidth != desiredWidth || scaledHeight != desiredHeight)
  698. throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
  699. }
  700. int pixelFormat; boolean intPixels = false;
  701. if (byteOrder == null)
  702. byteOrder = ByteOrder.nativeOrder();
  703. switch(dstImage.getType()) {
  704. case BufferedImage.TYPE_3BYTE_BGR:
  705. pixelFormat = TJ.PF_BGR; break;
  706. case BufferedImage.TYPE_4BYTE_ABGR:
  707. case BufferedImage.TYPE_4BYTE_ABGR_PRE:
  708. pixelFormat = TJ.PF_XBGR; break;
  709. case BufferedImage.TYPE_BYTE_GRAY:
  710. pixelFormat = TJ.PF_GRAY; break;
  711. case BufferedImage.TYPE_INT_BGR:
  712. if (byteOrder == ByteOrder.BIG_ENDIAN)
  713. pixelFormat = TJ.PF_XBGR;
  714. else
  715. pixelFormat = TJ.PF_RGBX;
  716. intPixels = true; break;
  717. case BufferedImage.TYPE_INT_RGB:
  718. if (byteOrder == ByteOrder.BIG_ENDIAN)
  719. pixelFormat = TJ.PF_XRGB;
  720. else
  721. pixelFormat = TJ.PF_BGRX;
  722. intPixels = true; break;
  723. case BufferedImage.TYPE_INT_ARGB:
  724. case BufferedImage.TYPE_INT_ARGB_PRE:
  725. if (byteOrder == ByteOrder.BIG_ENDIAN)
  726. pixelFormat = TJ.PF_ARGB;
  727. else
  728. pixelFormat = TJ.PF_BGRA;
  729. intPixels = true; break;
  730. default:
  731. throw new IllegalArgumentException("Unsupported BufferedImage format");
  732. }
  733. WritableRaster wr = dstImage.getRaster();
  734. if (intPixels) {
  735. SinglePixelPackedSampleModel sm =
  736. (SinglePixelPackedSampleModel)dstImage.getSampleModel();
  737. int stride = sm.getScanlineStride();
  738. DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
  739. int[] buf = db.getData();
  740. if (yuvImage != null)
  741. decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
  742. yuvImage.getStrides(), yuvImage.getSubsamp(), buf, 0, 0,
  743. yuvImage.getWidth(), stride, yuvImage.getHeight(),
  744. pixelFormat, flags);
  745. else {
  746. if (jpegBuf == null)
  747. throw new IllegalStateException(NO_ASSOC_ERROR);
  748. decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
  749. scaledHeight, pixelFormat, flags);
  750. }
  751. } else {
  752. ComponentSampleModel sm =
  753. (ComponentSampleModel)dstImage.getSampleModel();
  754. int pixelSize = sm.getPixelStride();
  755. if (pixelSize != TJ.getPixelSize(pixelFormat))
  756. throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
  757. int pitch = sm.getScanlineStride();
  758. DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
  759. byte[] buf = db.getData();
  760. decompress(buf, 0, 0, scaledWidth, pitch, scaledHeight, pixelFormat,
  761. flags);
  762. }
  763. }
  764. /**
  765. * Decompress the JPEG source image or decode the YUV source image associated
  766. * with this decompressor instance and return a <code>BufferedImage</code>
  767. * instance containing the decompressed/decoded image.
  768. *
  769. * @param desiredWidth see
  770. * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
  771. * description
  772. *
  773. * @param desiredHeight see
  774. * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
  775. * description
  776. *
  777. * @param bufferedImageType the image type of the <code>BufferedImage</code>
  778. * instance that will be created (for instance,
  779. * <code>BufferedImage.TYPE_INT_RGB</code>)
  780. *
  781. * @param flags the bitwise OR of one or more of
  782. * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
  783. *
  784. * @return a <code>BufferedImage</code> instance containing the
  785. * decompressed/decoded image.
  786. */
  787. public BufferedImage decompress(int desiredWidth, int desiredHeight,
  788. int bufferedImageType, int flags)
  789. throws TJException {
  790. if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
  791. flags < 0)
  792. throw new IllegalArgumentException("Invalid argument in decompress()");
  793. int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
  794. int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
  795. BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
  796. bufferedImageType);
  797. decompress(img, flags);
  798. return img;
  799. }
  800. /**
  801. * Free the native structures associated with this decompressor instance.
  802. */
  803. @Override
  804. public void close() throws TJException {
  805. if (handle != 0)
  806. destroy();
  807. }
  808. @Override
  809. protected void finalize() throws Throwable {
  810. try {
  811. close();
  812. } catch(TJException e) {
  813. } finally {
  814. super.finalize();
  815. }
  816. };
  817. private native void init() throws TJException;
  818. private native void destroy() throws TJException;
  819. private native void decompressHeader(byte[] srcBuf, int size)
  820. throws TJException;
  821. @Deprecated
  822. private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
  823. int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
  824. throws TJException;
  825. private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, int x,
  826. int y, int desiredWidth, int pitch, int desiredHeight, int pixelFormat,
  827. int flags) throws TJException;
  828. @Deprecated
  829. private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
  830. int desiredWidth, int stride, int desiredHeight, int pixelFormat,
  831. int flags) throws TJException;
  832. private native void decompress(byte[] srcBuf, int size, int[] dstBuf, int x,
  833. int y, int desiredWidth, int stride, int desiredHeight, int pixelFormat,
  834. int flags) throws TJException;
  835. @Deprecated
  836. private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
  837. int flags) throws TJException;
  838. private native void decompressToYUV(byte[] srcBuf, int size,
  839. byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
  840. int desiredheight, int flags) throws TJException;
  841. private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
  842. int[] srcStrides, int subsamp, byte[] dstBuf, int x, int y, int width,
  843. int pitch, int height, int pixelFormat, int flags) throws TJException;
  844. private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
  845. int[] srcStrides, int subsamp, int[] dstBuf, int x, int y, int width,
  846. int stride, int height, int pixelFormat, int flags) throws TJException;
  847. static {
  848. TJLoader.load();
  849. }
  850. protected long handle = 0;
  851. protected byte[] jpegBuf = null;
  852. protected int jpegBufSize = 0;
  853. protected YUVImage yuvImage = null;
  854. protected int jpegWidth = 0;
  855. protected int jpegHeight = 0;
  856. protected int jpegSubsamp = -1;
  857. protected int jpegColorspace = -1;
  858. private ByteOrder byteOrder = null;
  859. }