PageRenderTime 25ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/YCbCrPlanarUpsamplerStream.java

https://github.com/haraldk/TwelveMonkeys
Java | 198 lines | 121 code | 37 blank | 40 comment | 20 complexity | 2089de0e7101e03833b4a92579cd8460 MD5 | raw file
  1. /*
  2. * Copyright (c) 2022, Harald Kuhr
  3. * 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, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * * Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * * Neither the name of the copyright holder nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  25. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  26. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. package com.twelvemonkeys.imageio.plugins.tiff;
  31. import com.twelvemonkeys.lang.Validate;
  32. import java.io.EOFException;
  33. import java.io.FilterInputStream;
  34. import java.io.IOException;
  35. import java.io.InputStream;
  36. /**
  37. * Input stream that provides on-the-fly upsampling of TIFF subsampled YCbCr samples.
  38. *
  39. * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
  40. * @author last modified by $Author: haraldk$
  41. * @version $Id: YCbCrUpsamplerStream.java,v 1.0 31.01.13 09:25 haraldk Exp$
  42. */
  43. final class YCbCrPlanarUpsamplerStream extends FilterInputStream {
  44. private final int horizChromaSub;
  45. private final int vertChromaSub;
  46. private final int yCbCrPos;
  47. private final int columns;
  48. private final int units;
  49. private final byte[] decodedRows;
  50. int decodedLength;
  51. int decodedPos;
  52. private final byte[] buffer;
  53. int bufferLength;
  54. int bufferPos;
  55. public YCbCrPlanarUpsamplerStream(final InputStream stream, final int[] chromaSub, final int yCbCrPos, final int columns) {
  56. super(Validate.notNull(stream, "stream"));
  57. Validate.notNull(chromaSub, "chromaSub");
  58. Validate.isTrue(chromaSub.length == 2, "chromaSub.length != 2");
  59. this.horizChromaSub = chromaSub[0];
  60. this.vertChromaSub = chromaSub[1];
  61. this.yCbCrPos = yCbCrPos;
  62. this.columns = columns;
  63. units = (columns + horizChromaSub - 1) / horizChromaSub; // If columns % horizChromasSub != 0...
  64. // ...each coded row will be padded to fill unit
  65. decodedRows = new byte[columns * vertChromaSub];
  66. buffer = new byte[units];
  67. }
  68. private void fetch() throws IOException {
  69. if (bufferPos >= bufferLength) {
  70. int pos = 0;
  71. int read;
  72. // This *SHOULD* read an entire row of units into the buffer, otherwise decodeRows will throw EOFException
  73. while (pos < buffer.length && (read = in.read(buffer, pos, buffer.length - pos)) > 0) {
  74. pos += read;
  75. }
  76. bufferLength = pos;
  77. bufferPos = 0;
  78. }
  79. if (bufferLength > 0) {
  80. decodeRows();
  81. }
  82. else {
  83. decodedLength = -1;
  84. }
  85. }
  86. private void decodeRows() throws EOFException {
  87. decodedLength = decodedRows.length;
  88. for (int u = 0; u < units; u++) {
  89. if (u >= bufferLength) {
  90. throw new EOFException("Unexpected end of stream");
  91. }
  92. // Decode one unit
  93. byte c = buffer[u];
  94. for (int y = 0; y < vertChromaSub; y++) {
  95. for (int x = 0; x < horizChromaSub; x++) {
  96. // Skip padding at end of row
  97. int column = horizChromaSub * u + x;
  98. if (column >= columns) {
  99. break;
  100. }
  101. int pixelOff = column + columns * y;
  102. decodedRows[pixelOff] = c;
  103. }
  104. }
  105. }
  106. bufferPos = bufferLength;
  107. decodedPos = 0;
  108. }
  109. @Override
  110. public int read() throws IOException {
  111. if (decodedLength < 0) {
  112. return -1;
  113. }
  114. if (decodedPos >= decodedLength) {
  115. fetch();
  116. if (decodedLength < 0) {
  117. return -1;
  118. }
  119. }
  120. return decodedRows[decodedPos++] & 0xff;
  121. }
  122. @Override
  123. public int read(byte[] b, int off, int len) throws IOException {
  124. if (decodedLength < 0) {
  125. return -1;
  126. }
  127. if (decodedPos >= decodedLength) {
  128. fetch();
  129. if (decodedLength < 0) {
  130. return -1;
  131. }
  132. }
  133. int read = Math.min(decodedLength - decodedPos, len);
  134. System.arraycopy(decodedRows, decodedPos, b, off, read);
  135. decodedPos += read;
  136. return read;
  137. }
  138. @Override
  139. public long skip(long n) throws IOException {
  140. if (decodedLength < 0) {
  141. return -1;
  142. }
  143. if (decodedPos >= decodedLength) {
  144. fetch();
  145. if (decodedLength < 0) {
  146. return -1;
  147. }
  148. }
  149. int skipped = (int) Math.min(decodedLength - decodedPos, n);
  150. decodedPos += skipped;
  151. return skipped;
  152. }
  153. @Override
  154. public boolean markSupported() {
  155. return false;
  156. }
  157. @Override
  158. public synchronized void reset() throws IOException {
  159. throw new IOException("mark/reset not supported");
  160. }
  161. }