private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf, int flags) throws Exception { int rshift = TJ.getRedOffset(pf) * 8; int gshift = TJ.getGreenOffset(pf) * 8; int bshift = TJ.getBlueOffset(pf) * 8; int ashift = alphaOffset[pf] * 8; int index, row, col, halfway = 16; Arrays.fill(buf, 0); for (row = 0; row < h; row++) { for (col = 0; col < w; col++) { if ((flags & TJ.FLAG_BOTTOMUP) != 0) index = pitch * (h - row - 1) + col; else index = pitch * row + col; if (((row / 8) + (col / 8)) % 2 == 0) { if (row < halfway) { buf[index] |= (255 << rshift); buf[index] |= (255 << gshift); buf[index] |= (255 << bshift); } } else { buf[index] |= (255 << rshift); if (row >= halfway) buf[index] |= (255 << gshift); } if (ashift >= 0) buf[index] |= (255 << ashift); } } }
/** * Encode the uncompressed source image stored in <code>srcImage</code> and output a YUV planar * image to the given destination buffer. See {@link #encodeYUV(byte[], int)} for more detail. * * @param srcImage a <code>BufferedImage</code> instance containing RGB or grayscale pixels to be * encoded * @param dstBuf buffer that will receive the YUV planar image. Use {@link TJ#bufSizeYUV} to * determine the appropriate size for this buffer based on the image width, height, and level * of chrominance subsampling. * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} */ public void encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags) throws Exception { if (srcImage == null || dstBuf == null || flags < 0) throw new Exception("Invalid argument in encodeYUV()"); int width = srcImage.getWidth(); int height = srcImage.getHeight(); int pixelFormat; boolean intPixels = false; if (byteOrder == null) byteOrder = ByteOrder.nativeOrder(); switch (srcImage.getType()) { case BufferedImage.TYPE_3BYTE_BGR: pixelFormat = TJ.PF_BGR; break; case BufferedImage.TYPE_4BYTE_ABGR: case BufferedImage.TYPE_4BYTE_ABGR_PRE: pixelFormat = TJ.PF_XBGR; break; case BufferedImage.TYPE_BYTE_GRAY: pixelFormat = TJ.PF_GRAY; break; case BufferedImage.TYPE_INT_BGR: if (byteOrder == ByteOrder.BIG_ENDIAN) pixelFormat = TJ.PF_XBGR; else pixelFormat = TJ.PF_RGBX; intPixels = true; break; case BufferedImage.TYPE_INT_RGB: case BufferedImage.TYPE_INT_ARGB: case BufferedImage.TYPE_INT_ARGB_PRE: if (byteOrder == ByteOrder.BIG_ENDIAN) pixelFormat = TJ.PF_XRGB; else pixelFormat = TJ.PF_BGRX; intPixels = true; break; default: throw new Exception("Unsupported BufferedImage format"); } WritableRaster wr = srcImage.getRaster(); if (subsamp < 0) throw new Exception("Subsampling level not set"); if (intPixels) { SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel) srcImage.getSampleModel(); int pitch = sm.getScanlineStride(); DataBufferInt db = (DataBufferInt) wr.getDataBuffer(); int[] buf = db.getData(); encodeYUV(buf, width, pitch, height, pixelFormat, dstBuf, subsamp, flags); } else { ComponentSampleModel sm = (ComponentSampleModel) srcImage.getSampleModel(); int pixelSize = sm.getPixelStride(); if (pixelSize != TJ.getPixelSize(pixelFormat)) throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage"); int pitch = sm.getScanlineStride(); DataBufferByte db = (DataBufferByte) wr.getDataBuffer(); byte[] buf = db.getData(); encodeYUV(buf, width, pitch, height, pixelFormat, dstBuf, subsamp, flags); } compressedSize = TJ.bufSizeYUV(width, height, subsamp); }
/** * Compress the uncompressed source image stored in <code>srcImage</code> and return a buffer * containing a JPEG image. * * @param srcImage a <code>BufferedImage</code> instance containing RGB or grayscale pixels to be * compressed * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} * @return a buffer containing a JPEG image. The length of this buffer will not be equal to the * size of the JPEG image. Use {@link #getCompressedSize} to obtain the size of the JPEG * image. */ public byte[] compress(BufferedImage srcImage, int flags) throws Exception { int width = srcImage.getWidth(); int height = srcImage.getHeight(); byte[] buf = new byte[TJ.bufSize(width, height, subsamp)]; compress(srcImage, buf, flags); return buf; }
/** * Encode the uncompressed source image associated with this compressor instance and output a YUV * planar image to the given destination buffer. This method uses the accelerated color conversion * routines in TurboJPEG's underlying codec to produce a planar YUV image that is suitable for * direct video display. Specifically, if the chrominance components are subsampled along the * horizontal dimension, then the width of the luminance plane is padded to 2 in the output image * (same goes for the height of the luminance plane, if the chrominance components are subsampled * along the vertical dimension.) Also, each line of each plane in the output image is padded to 4 * bytes. Although this will work with any subsampling option, it is really only useful in * combination with {@link TJ#SAMP_420}, which produces an image compatible with the I420 (AKA * "YUV420P") format. * * @param dstBuf buffer that will receive the YUV planar image. Use {@link TJ#bufSizeYUV} to * determine the appropriate size for this buffer based on the image width, height, and level * of chrominance subsampling. * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} */ public void encodeYUV(byte[] dstBuf, int flags) throws Exception { if (dstBuf == null || flags < 0) throw new Exception("Invalid argument in compress()"); if (srcBuf == null) throw new Exception(NO_ASSOC_ERROR); if (subsamp < 0) throw new Exception("Subsampling level not set"); encodeYUV(srcBuf, srcWidth, srcPitch, srcHeight, srcPixelFormat, dstBuf, subsamp, flags); compressedSize = TJ.bufSizeYUV(srcWidth, srcHeight, subsamp); }
/** * Encode the uncompressed source image associated with this compressor instance and return a * buffer containing a YUV planar image. See {@link #encodeYUV(byte[], int)} for more detail. * * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} * @return a buffer containing a YUV planar image */ public byte[] encodeYUV(int flags) throws Exception { if (srcWidth < 1 || srcHeight < 1) throw new Exception(NO_ASSOC_ERROR); if (subsamp < 0) throw new Exception("Subsampling level not set"); byte[] buf = new byte[TJ.bufSizeYUV(srcWidth, srcHeight, subsamp)]; encodeYUV(buf, flags); return buf; }
/** * Encode the uncompressed source image stored in <code>srcImage</code> and return a buffer * containing a YUV planar image. See {@link #encodeYUV(byte[], int)} for more detail. * * @param srcImage a <code>BufferedImage</code> instance containing RGB or grayscale pixels to be * encoded * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} * @return a buffer containing a YUV planar image */ public byte[] encodeYUV(BufferedImage srcImage, int flags) throws Exception { if (subsamp < 0) throw new Exception("Subsampling level not set"); int width = srcImage.getWidth(); int height = srcImage.getHeight(); byte[] buf = new byte[TJ.bufSizeYUV(width, height, subsamp)]; encodeYUV(srcImage, buf, flags); return buf; }
/** * Decompress the JPEG source image associated with this decompressor instance and return a buffer * containing a YUV planar image. See {@link #decompressToYUV(byte[], int)} for more detail. * * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} * @return a buffer containing a YUV planar image */ public byte[] decompressToYUV(int flags) throws Exception { if (flags < 0) throw new Exception("Invalid argument in decompressToYUV()"); if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0) throw new Exception(NO_ASSOC_ERROR); if (jpegSubsamp >= TJ.NUMSAMP) throw new Exception("JPEG header information is invalid"); byte[] buf = new byte[TJ.bufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)]; decompressToYUV(buf, flags); return buf; }
private static void doTest(int w, int h, int[] formats, int subsamp, String baseName) throws Exception { TJCompressor tjc = null; TJDecompressor tjd = null; int size; byte[] dstBuf; if (yuv == YUVENCODE) dstBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)]; else dstBuf = new byte[TJ.bufSize(w, h, subsamp)]; try { tjc = new TJCompressor(); tjd = new TJDecompressor(); for (int pf : formats) { for (int i = 0; i < 2; i++) { int flags = 0; if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 || subsamp == TJ.SAMP_440) flags |= TJ.FLAG_FASTUPSAMPLE; if (i == 1) { if (yuv == YUVDECODE) { tjc.close(); tjd.close(); return; } else flags |= TJ.FLAG_BOTTOMUP; } size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100, flags); decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags); if (pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi) decompTest( tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX), baseName, subsamp, flags); } } } catch (Exception e) { if (tjc != null) tjc.close(); if (tjd != null) tjd.close(); throw e; } if (tjc != null) tjc.close(); if (tjd != null) tjd.close(); }
private static void bufSizeTest() throws Exception { int w, h, i, subsamp; byte[] srcBuf, jpegBuf; TJCompressor tjc = null; Random r = new Random(); try { tjc = new TJCompressor(); System.out.println("Buffer size regression test"); for (subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) { for (w = 1; w < 48; w++) { int maxh = (w == 1) ? 2048 : 48; for (h = 1; h < maxh; h++) { if (h % 100 == 0) System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h); srcBuf = new byte[w * h * 4]; jpegBuf = new byte[TJ.bufSize(w, h, subsamp)]; for (i = 0; i < w * h * 4; i++) { srcBuf[i] = (byte) (r.nextInt(2) * 255); } tjc.setSourceImage(srcBuf, w, 0, h, TJ.PF_BGRX); tjc.setSubsamp(subsamp); tjc.setJPEGQuality(100); tjc.compress(jpegBuf, 0); srcBuf = new byte[h * w * 4]; jpegBuf = new byte[TJ.bufSize(h, w, subsamp)]; for (i = 0; i < h * w * 4; i++) { srcBuf[i] = (byte) (r.nextInt(2) * 255); } tjc.setSourceImage(srcBuf, h, 0, w, TJ.PF_BGRX); tjc.compress(jpegBuf, 0); } } } System.out.println("Done. "); } catch (Exception e) { if (tjc != null) tjc.close(); throw e; } if (tjc != null) tjc.close(); }
private static void initBuf(byte[] buf, int w, int pitch, int h, int pf, int flags) throws Exception { int roffset = TJ.getRedOffset(pf); int goffset = TJ.getGreenOffset(pf); int boffset = TJ.getBlueOffset(pf); int aoffset = alphaOffset[pf]; int ps = TJ.getPixelSize(pf); int index, row, col, halfway = 16; Arrays.fill(buf, (byte) 0); if (pf == TJ.PF_GRAY) { for (row = 0; row < h; row++) { for (col = 0; col < w; col++) { if ((flags & TJ.FLAG_BOTTOMUP) != 0) index = pitch * (h - row - 1) + col; else index = pitch * row + col; if (((row / 8) + (col / 8)) % 2 == 0) buf[index] = (row < halfway) ? (byte) 255 : 0; else buf[index] = (row < halfway) ? 76 : (byte) 226; } } return; } for (row = 0; row < h; row++) { for (col = 0; col < w; col++) { if ((flags & TJ.FLAG_BOTTOMUP) != 0) index = pitch * (h - row - 1) + col * ps; else index = pitch * row + col * ps; if (((row / 8) + (col / 8)) % 2 == 0) { if (row < halfway) { buf[index + roffset] = (byte) 255; buf[index + goffset] = (byte) 255; buf[index + boffset] = (byte) 255; } } else { buf[index + roffset] = (byte) 255; if (row >= halfway) buf[index + goffset] = (byte) 255; } if (aoffset >= 0) buf[index + aoffset] = (byte) 255; } } }
/** * Decompress the JPEG source image associated with this decompressor instance and return a buffer * containing the decompressed image. * * @param desiredWidth see {@link #decompress(byte[], int, int, int, int, int, int, int)} for * description * @param pitch see {@link #decompress(byte[], int, int, int, int, int, int, int)} for description * @param desiredHeight see {@link #decompress(byte[], int, int, int, int, int, int, int)} for * description * @param pixelFormat pixel format of the decompressed image (one of {@link TJ TJ.PF_*}) * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} * @return a buffer containing the decompressed image */ public byte[] decompress( int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags) throws Exception { if (desiredWidth < 0 || pitch < 0 || desiredHeight < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0) throw new Exception("Invalid argument in decompress()"); int pixelSize = TJ.getPixelSize(pixelFormat); int scaledWidth = getScaledWidth(desiredWidth, desiredHeight); int scaledHeight = getScaledHeight(desiredWidth, desiredHeight); if (pitch == 0) pitch = scaledWidth * pixelSize; byte[] buf = new byte[pitch * scaledHeight]; decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags); return buf; }
/** * Returns the height of the largest scaled-down image that the TurboJPEG decompressor can * generate without exceeding the desired image width and height. * * @param desiredWidth desired width (in pixels) of the decompressed image. Setting this to 0 is * the same as setting it to the width of the JPEG image (in other words, the width will not * be considered when determining the scaled image size.) * @param desiredHeight desired height (in pixels) of the decompressed image. Setting this to 0 is * the same as setting it to the height of the JPEG image (in other words, the height will not * be considered when determining the scaled image size.) * @return the height of the largest scaled-down image that the TurboJPEG decompressor can * generate without exceeding the desired image width and height */ public int getScaledHeight(int desiredWidth, int desiredHeight) throws Exception { if (jpegWidth < 1 || jpegHeight < 1) throw new Exception(NO_ASSOC_ERROR); if (desiredWidth < 0 || desiredHeight < 0) throw new Exception("Invalid argument in getScaledHeight()"); TJScalingFactor[] sf = TJ.getScalingFactors(); if (desiredWidth == 0) desiredWidth = jpegWidth; if (desiredHeight == 0) desiredHeight = jpegHeight; int scaledWidth = jpegWidth, scaledHeight = jpegHeight; for (int i = 0; i < sf.length; i++) { scaledWidth = sf[i].getScaled(jpegWidth); scaledHeight = sf[i].getScaled(jpegHeight); if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight) break; } if (scaledWidth > desiredWidth || scaledHeight > desiredHeight) throw new Exception("Could not scale down to desired image dimensions"); return scaledHeight; }
private static void decompTest( TJDecompressor tjd, byte[] jpegBuf, int jpegSize, int w, int h, int pf, String baseName, int subsamp, int flags) throws Exception { int i; if ((subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY) && yuv == 0) { TJScalingFactor sf[] = TJ.getScalingFactors(); for (i = 0; i < sf.length; i++) decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp, flags, sf[i]); } else decompTest( tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp, flags, new TJScalingFactor(1, 1)); System.out.print("\n"); }
/** * Associate an uncompressed source image with this compressor instance. * * @param srcImage image buffer containing RGB or grayscale pixels to be compressed * @param x x offset (in pixels) of the region from which the JPEG image should be compressed, * relative to the start of <code>srcImage</code>. * @param y y offset (in pixels) of the region from which the JPEG image should be compressed, * relative to the start of <code>srcImage</code>. * @param width width (in pixels) of the region in the source image from which the JPEG image * should be compressed. * @param pitch bytes per line of the source image. Normally, this should be <code> * width * TJ.pixelSize(pixelFormat)</code> if the source image is unpadded, but you can use * this parameter to, for instance, specify that the scanlines in the source image are padded * to a 4-byte boundary or to compress a JPEG image from a region of a larger source image. * You can also be clever and use this parameter to skip lines, etc. Setting this parameter to * 0 is the equivalent of setting it to <code>width * * TJ.pixelSize(pixelFormat)</code>. * @param height height (in pixels) of the region in the source image from which the JPEG image * should be compressed. * @param pixelFormat pixel format of the source image (one of {@link TJ TJ.PF_*}) */ public void setSourceImage( byte[] srcImage, int x, int y, int width, int pitch, int height, int pixelFormat) throws Exception { if (handle == 0) init(); if (srcImage == null || x < 0 || y < 0 || width < 1 || height < 1 || pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF) throw new Exception("Invalid argument in setSourceImage()"); srcBuf = srcImage; srcWidth = width; if (pitch == 0) srcPitch = width * TJ.getPixelSize(pixelFormat); else srcPitch = pitch; srcHeight = height; srcPixelFormat = pixelFormat; srcX = x; srcY = y; }
/** * Decompress the JPEG source image associated with this decompressor instance and output a * decompressed image to the given <code>BufferedImage</code> instance. * * @param dstImage a <code>BufferedImage</code> instance that will receive the decompressed image * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} */ public void decompress(BufferedImage dstImage, int flags) throws Exception { if (dstImage == null || flags < 0) throw new Exception("Invalid argument in decompress()"); int desiredWidth = dstImage.getWidth(); int desiredHeight = dstImage.getHeight(); int scaledWidth = getScaledWidth(desiredWidth, desiredHeight); int scaledHeight = getScaledHeight(desiredWidth, desiredHeight); if (scaledWidth != desiredWidth || scaledHeight != desiredHeight) throw new Exception( "BufferedImage dimensions do not match a scaled image size that TurboJPEG is capable of generating."); int pixelFormat; boolean intPixels = false; if (byteOrder == null) byteOrder = ByteOrder.nativeOrder(); switch (dstImage.getType()) { case BufferedImage.TYPE_3BYTE_BGR: pixelFormat = TJ.PF_BGR; break; case BufferedImage.TYPE_4BYTE_ABGR: case BufferedImage.TYPE_4BYTE_ABGR_PRE: pixelFormat = TJ.PF_XBGR; break; case BufferedImage.TYPE_BYTE_GRAY: pixelFormat = TJ.PF_GRAY; break; case BufferedImage.TYPE_INT_BGR: if (byteOrder == ByteOrder.BIG_ENDIAN) pixelFormat = TJ.PF_XBGR; else pixelFormat = TJ.PF_RGBX; intPixels = true; break; case BufferedImage.TYPE_INT_RGB: if (byteOrder == ByteOrder.BIG_ENDIAN) pixelFormat = TJ.PF_XRGB; else pixelFormat = TJ.PF_BGRX; intPixels = true; break; case BufferedImage.TYPE_INT_ARGB: case BufferedImage.TYPE_INT_ARGB_PRE: if (byteOrder == ByteOrder.BIG_ENDIAN) pixelFormat = TJ.PF_ARGB; else pixelFormat = TJ.PF_BGRA; intPixels = true; break; default: throw new Exception("Unsupported BufferedImage format"); } WritableRaster wr = dstImage.getRaster(); if (intPixels) { SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel) dstImage.getSampleModel(); int stride = sm.getScanlineStride(); DataBufferInt db = (DataBufferInt) wr.getDataBuffer(); int[] buf = db.getData(); if (jpegBuf == null) throw new Exception(NO_ASSOC_ERROR); decompress(jpegBuf, jpegBufSize, buf, scaledWidth, stride, scaledHeight, pixelFormat, flags); } else { ComponentSampleModel sm = (ComponentSampleModel) dstImage.getSampleModel(); int pixelSize = sm.getPixelStride(); if (pixelSize != TJ.getPixelSize(pixelFormat)) throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage"); int pitch = sm.getScanlineStride(); DataBufferByte db = (DataBufferByte) wr.getDataBuffer(); byte[] buf = db.getData(); decompress(buf, scaledWidth, pitch, scaledHeight, pixelFormat, flags); } }
private static void decompTest( TJDecompressor tjd, byte[] jpegBuf, int jpegSize, int w, int h, int pf, String baseName, int subsamp, int flags, TJScalingFactor sf) throws Exception { String pfStr, tempstr; double t; int scaledWidth = sf.getScaled(w); int scaledHeight = sf.getScaled(h); int temp1, temp2, imgType = pf; BufferedImage img = null; byte[] dstBuf = null; if (yuv == YUVENCODE) return; if (bi) { pf = biTypePF(imgType); pfStr = biTypeStr(imgType); } else pfStr = pixFormatStr[pf]; System.out.print("JPEG -> "); if (yuv == YUVDECODE) System.out.print("YUV " + subName[subsamp] + " ... "); else { System.out.print(pfStr + " "); if (bi) System.out.print("(" + pixFormatStr[pf] + ") "); if ((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up "); else System.out.print("Top-Down "); if (!sf.isOne()) System.out.print(sf.getNum() + "/" + sf.getDenom() + " ... "); else System.out.print("... "); } t = getTime(); tjd.setJPEGImage(jpegBuf, jpegSize); if (tjd.getWidth() != w || tjd.getHeight() != h || tjd.getSubsamp() != subsamp) throw new Exception("Incorrect JPEG header"); temp1 = scaledWidth; temp2 = scaledHeight; temp1 = tjd.getScaledWidth(temp1, temp2); temp2 = tjd.getScaledHeight(temp1, temp2); if (temp1 != scaledWidth || temp2 != scaledHeight) throw new Exception("Scaled size mismatch"); if (yuv == YUVDECODE) dstBuf = tjd.decompressToYUV(flags); else { if (bi) img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags); else dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags); } t = getTime() - t; if (bi) { tempstr = baseName + "_dec_" + pfStr + "_" + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" + subName[subsamp] + "_" + (double) sf.getNum() / (double) sf.getDenom() + "x" + ".png"; File file = new File(tempstr); ImageIO.write(img, "png", file); } if (yuv == YUVDECODE) { if (checkBufYUV(dstBuf, dstBuf.length, w, h, subsamp) == 1) System.out.print("Passed."); else { System.out.print("FAILED!"); exitStatus = -1; } } else { if ((bi && checkImg(img, pf, subsamp, sf, flags) == 1) || (!bi && checkBuf( dstBuf, scaledWidth, scaledWidth * TJ.getPixelSize(pf), scaledHeight, pf, subsamp, sf, flags) == 1)) System.out.print("Passed."); else { System.out.print("FAILED!"); exitStatus = -1; } } System.out.format(" %.6f ms\n", t * 1000.); }
private static int checkBuf( byte[] buf, int w, int pitch, int h, int pf, int subsamp, TJScalingFactor sf, int flags) throws Exception { int roffset = TJ.getRedOffset(pf); int goffset = TJ.getGreenOffset(pf); int boffset = TJ.getBlueOffset(pf); int aoffset = alphaOffset[pf]; int ps = TJ.getPixelSize(pf); int index, row, col, retval = 1; int halfway = 16 * sf.getNum() / sf.getDenom(); int blockSize = 8 * sf.getNum() / sf.getDenom(); try { for (row = 0; row < halfway; row++) { for (col = 0; col < w; col++) { if ((flags & TJ.FLAG_BOTTOMUP) != 0) index = pitch * (h - row - 1) + col * ps; else index = pitch * row + col * ps; byte r = buf[index + roffset]; byte g = buf[index + goffset]; byte b = buf[index + boffset]; byte a = aoffset >= 0 ? buf[index + aoffset] : (byte) 255; if (((row / blockSize) + (col / blockSize)) % 2 == 0) { if (row < halfway) { checkVal255(row, col, r, "R"); checkVal255(row, col, g, "G"); checkVal255(row, col, b, "B"); } else { checkVal0(row, col, r, "R"); checkVal0(row, col, g, "G"); checkVal0(row, col, b, "B"); } } else { if (subsamp == TJ.SAMP_GRAY) { if (row < halfway) { checkVal(row, col, r, "R", 76); checkVal(row, col, g, "G", 76); checkVal(row, col, b, "B", 76); } else { checkVal(row, col, r, "R", 226); checkVal(row, col, g, "G", 226); checkVal(row, col, b, "B", 226); } } else { checkVal255(row, col, r, "R"); if (row < halfway) { checkVal0(row, col, g, "G"); } else { checkVal255(row, col, g, "G"); } checkVal0(row, col, b, "B"); } } checkVal255(row, col, a, "A"); } } } catch (Exception e) { System.out.println(e); retval = 0; } if (retval == 0) { System.out.print("\n"); for (row = 0; row < h; row++) { for (col = 0; col < w; col++) { int r = buf[pitch * row + col * ps + roffset]; int g = buf[pitch * row + col * ps + goffset]; int b = buf[pitch * row + col * ps + boffset]; if (r < 0) r += 256; if (g < 0) g += 256; if (b < 0) b += 256; System.out.format("%3d/%3d/%3d ", r, g, b); } System.out.print("\n"); } } return retval; }
private static int checkIntBuf( int[] buf, int w, int pitch, int h, int pf, int subsamp, TJScalingFactor sf, int flags) throws Exception { int rshift = TJ.getRedOffset(pf) * 8; int gshift = TJ.getGreenOffset(pf) * 8; int bshift = TJ.getBlueOffset(pf) * 8; int ashift = alphaOffset[pf] * 8; int index, row, col, retval = 1; int halfway = 16 * sf.getNum() / sf.getDenom(); int blockSize = 8 * sf.getNum() / sf.getDenom(); try { for (row = 0; row < halfway; row++) { for (col = 0; col < w; col++) { if ((flags & TJ.FLAG_BOTTOMUP) != 0) index = pitch * (h - row - 1) + col; else index = pitch * row + col; int r = (buf[index] >> rshift) & 0xFF; int g = (buf[index] >> gshift) & 0xFF; int b = (buf[index] >> bshift) & 0xFF; int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255; if (((row / blockSize) + (col / blockSize)) % 2 == 0) { if (row < halfway) { checkVal255(row, col, r, "R"); checkVal255(row, col, g, "G"); checkVal255(row, col, b, "B"); } else { checkVal0(row, col, r, "R"); checkVal0(row, col, g, "G"); checkVal0(row, col, b, "B"); } } else { if (subsamp == TJ.SAMP_GRAY) { if (row < halfway) { checkVal(row, col, r, "R", 76); checkVal(row, col, g, "G", 76); checkVal(row, col, b, "B", 76); } else { checkVal(row, col, r, "R", 226); checkVal(row, col, g, "G", 226); checkVal(row, col, b, "B", 226); } } else { checkVal255(row, col, r, "R"); if (row < halfway) { checkVal0(row, col, g, "G"); } else { checkVal255(row, col, g, "G"); } checkVal0(row, col, b, "B"); } } checkVal255(row, col, a, "A"); } } } catch (Exception e) { System.out.println(e); retval = 0; } if (retval == 0) { System.out.print("\n"); for (row = 0; row < h; row++) { for (col = 0; col < w; col++) { int r = (buf[pitch * row + col] >> rshift) & 0xFF; int g = (buf[pitch * row + col] >> gshift) & 0xFF; int b = (buf[pitch * row + col] >> bshift) & 0xFF; if (r < 0) r += 256; if (g < 0) g += 256; if (b < 0) b += 256; System.out.format("%3d/%3d/%3d ", r, g, b); } System.out.print("\n"); } } return retval; }
private static int checkBufYUV(byte[] buf, int size, int w, int h, int subsamp) throws Exception { int row, col; int hsf = TJ.getMCUWidth(subsamp) / 8, vsf = TJ.getMCUHeight(subsamp) / 8; int pw = PAD(w, hsf), ph = PAD(h, vsf); int cw = pw / hsf, ch = ph / vsf; int ypitch = PAD(pw, 4), uvpitch = PAD(cw, 4); int retval = 1; int correctsize = ypitch * ph + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2); int halfway = 16; try { if (size != correctsize) throw new Exception("\nIncorrect size " + size + ". Should be " + correctsize); for (row = 0; row < ph; row++) { for (col = 0; col < pw; col++) { byte y = buf[ypitch * row + col]; if (((row / 8) + (col / 8)) % 2 == 0) { if (row < halfway) checkVal255(row, col, y, "Y"); else checkVal0(row, col, y, "Y"); } else { if (row < halfway) checkVal(row, col, y, "Y", 76); else checkVal(row, col, y, "Y", 226); } } } if (subsamp != TJ.SAMP_GRAY) { halfway = 16 / vsf; for (row = 0; row < ch; row++) { for (col = 0; col < cw; col++) { byte u = buf[ypitch * ph + (uvpitch * row + col)], v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]; if (((row * vsf / 8) + (col * hsf / 8)) % 2 == 0) { checkVal(row, col, u, "U", 128); checkVal(row, col, v, "V", 128); } else { if (row < halfway) { checkVal(row, col, u, "U", 85); checkVal255(row, col, v, "V"); } else { checkVal0(row, col, u, "U"); checkVal(row, col, v, "V", 149); } } } } } } catch (Exception e) { System.out.println(e); retval = 0; } if (retval == 0) { for (row = 0; row < ph; row++) { for (col = 0; col < pw; col++) { int y = buf[ypitch * row + col]; if (y < 0) y += 256; System.out.format("%3d ", y); } System.out.print("\n"); } System.out.print("\n"); for (row = 0; row < ch; row++) { for (col = 0; col < cw; col++) { int u = buf[ypitch * ph + (uvpitch * row + col)]; if (u < 0) u += 256; System.out.format("%3d ", u); } System.out.print("\n"); } System.out.print("\n"); for (row = 0; row < ch; row++) { for (col = 0; col < cw; col++) { int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]; if (v < 0) v += 256; System.out.format("%3d ", v); } System.out.print("\n"); } System.out.print("\n"); } return retval; }
private static int compTest( TJCompressor tjc, byte[] dstBuf, int w, int h, int pf, String baseName, int subsamp, int jpegQual, int flags) throws Exception { String tempstr; byte[] srcBuf = null; BufferedImage img = null; String pfStr; double t; int size = 0, ps, imgType = pf; if (bi) { pf = biTypePF(imgType); pfStr = biTypeStr(imgType); } else pfStr = pixFormatStr[pf]; ps = TJ.getPixelSize(pf); System.out.print(pfStr + " "); if (bi) System.out.print("(" + pixFormatStr[pf] + ") "); if ((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up"); else System.out.print("Top-Down "); System.out.print(" -> " + subNameLong[subsamp] + " "); if (yuv == YUVENCODE) System.out.print("YUV ... "); else System.out.print("Q" + jpegQual + " ... "); if (bi) { img = new BufferedImage(w, h, imgType); initImg(img, pf, flags); tempstr = baseName + "_enc_" + pfStr + "_" + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" + subName[subsamp] + "_Q" + jpegQual + ".png"; File file = new File(tempstr); ImageIO.write(img, "png", file); } else { srcBuf = new byte[w * h * ps + 1]; initBuf(srcBuf, w, w * ps, h, pf, flags); } Arrays.fill(dstBuf, (byte) 0); t = getTime(); tjc.setSubsamp(subsamp); tjc.setJPEGQuality(jpegQual); if (bi) { if (yuv == YUVENCODE) tjc.encodeYUV(img, dstBuf, flags); else tjc.compress(img, dstBuf, flags); } else { tjc.setSourceImage(srcBuf, w, 0, h, pf); if (yuv == YUVENCODE) tjc.encodeYUV(dstBuf, flags); else tjc.compress(dstBuf, flags); } size = tjc.getCompressedSize(); t = getTime() - t; if (yuv == YUVENCODE) tempstr = baseName + "_enc_" + pfStr + "_" + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" + subName[subsamp] + ".yuv"; else tempstr = baseName + "_enc_" + pfStr + "_" + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" + subName[subsamp] + "_Q" + jpegQual + ".jpg"; writeJPEG(dstBuf, size, tempstr); if (yuv == YUVENCODE) { if (checkBufYUV(dstBuf, size, w, h, subsamp) == 1) System.out.print("Passed."); else { System.out.print("FAILED!"); exitStatus = -1; } } else System.out.print("Done."); System.out.format(" %.6f ms\n", t * 1000.); System.out.println(" Result in " + tempstr); return size; }
/** * Compress the uncompressed source image associated with this compressor instance and return a * buffer containing a JPEG image. * * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*} * @return a buffer containing a JPEG image. The length of this buffer will not be equal to the * size of the JPEG image. Use {@link #getCompressedSize} to obtain the size of the JPEG * image. */ public byte[] compress(int flags) throws Exception { if (srcWidth < 1 || srcHeight < 1) throw new Exception(NO_ASSOC_ERROR); byte[] buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)]; compress(buf, flags); return buf; }