在没有解密的情况下,将byte 中的加密图像转换为java中的BufferedImage

我需要将存储在byte[]加密图像转换为BufferedImage 。 我使用了以下代码:

 InputStream in = new ByteArrayInputStream(imageInByte); BufferedImage bImageFromConvert = ImageIO.read(in); 

但是bImageFromConvert为null。 我用谷歌搜索并找到了它的原因,因为图像是加密的,ImageIO无法读取它。 堆栈溢出中建议的解决方案是解密图像然后进行转换。 但它不适用于我的情况,因为我需要在这个加密的图像中嵌入一条消息,并使用下面的代码:

 public class EmbedMessage { //BufferedImage sourceImage,embeddedImage; public static BufferedImage embedMsg(BufferedImage sourceImage,String mess) { //String mess = "hai"; BufferedImage embeddedImage = sourceImage.getSubimage(0,0, sourceImage.getWidth(),sourceImage.getHeight()); embedMessage(embeddedImage, mess); return embeddedImage; } private static void embedMessage(BufferedImage img, String mess) { int messageLength = mess.length(); int imageWidth = img.getWidth(), imageHeight = img.getHeight(), imageSize = imageWidth * imageHeight; if(messageLength * 8 + 32 > imageSize) { return; } embedInteger(img, messageLength, 0, 0); byte b[] = mess.getBytes(); for(int i=0; i<b.length; i++) embedByte(img, b[i], i*8+32, 0); } private static void embedInteger(BufferedImage img, int n, int start, int storageBit) { int maxX = img.getWidth(), maxY = img.getHeight(), startX = start/maxY, startY = start - startX*maxY, count=0; for(int i=startX; i<maxX && count<32; i++) { for(int j=startY; j<maxY && count<32; j++) { int rgb = img.getRGB(i, j), bit = getBitValue(n, count); rgb = setBitValue(rgb, storageBit, bit); img.setRGB(i, j, rgb); count++; } } } private static void embedByte(BufferedImage img, byte b, int start, int storageBit) { int maxX = img.getWidth(), maxY = img.getHeight(), startX = start/maxY, startY = start - startX*maxY, count=0; for(int i=startX; i<maxX && count<8; i++) { for(int j=startY; j<maxY && count<8; j++) { int rgb = img.getRGB(i, j), bit = getBitValue(b, count); rgb = setBitValue(rgb, storageBit, bit); img.setRGB(i, j, rgb); count++; } } } private static int getBitValue(int n, int location) { int v = n & (int) Math.round(Math.pow(2, location)); return v==0?0:1; } private static int setBitValue(int n, int location, int bit) { int toggle = (int) Math.pow(2, location), bv = getBitValue(n, location); if(bv == bit) return n; if(bv == 0 && bit == 1) n |= toggle; else if(bv == 1 && bit == 0) n ^= toggle; return n; } } 

请建议我将byte array加密图像转换为BufferedImage

找到解决方案atlast。 感谢http://blog.philippheckel.com/2013/03/02/java-encode-any-byte-array-stream-or-file-into-a-24-bit-bitmap-bmp/ 。

加密的图像无法打开,因为其标题也已加密。 因此,为了在不解密的情况下打开它,我们必须加密除头部之外的部分或完全加密图像并附加另一个头部以使其成为新图像。使用类BitmapEncoder我已经附加或转换了加密的字节数组图像如下:

  File uploadedFile = new File(filePath); item.write(uploadedFile); //Convert uploaded image to byte[] for encryption bFile = new byte[(int) uploadedFile.length()]; try { FileInputStream fileInputStream = new FileInputStream(uploadedFile); //convert file into array of bytes fileInputStream.read(bFile); fileInputStream.close(); } catch (Exception e) { e.printStackTrace(); } //encrypt the byte array Cipher cipher=Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); enFile=cipher.doFinal(bFile); //save encrypted image to database image.setImage(enFile); //save this row to database UploadService ups=new UploadService(); imgid=ups.uploadImage(image); //Attach bitmap header to the encrypted byte array so that encrypted array can be still recognized as an image and save it to disk BitmapEncoder.encodeToBitmap(enFile, new File(uploadFolder + File.separator +"encrypted"+fileName)); 

希望这有助于其他人。

我粘贴完整的BitmapEncoder.java以避免链接问题:

  /* * BitmapEncoder, encodes any byte array, stream or file into a 24-bit bitmap (BMP). * Copyright (C) 2013 Philipp C. Heckel  * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; /** * Encodes any byte array, stream or file into a 24-bit bitmap (BMP). * * The encodeToBitmap()-methods can be used to transform any binary data * into a rectangular image and stored in the widely supported 24-bit bitmap * format. The method does not hide, encrypt or compress the source data in any * way. It merely prepends a bitmap header and transforms the payload as * specified by the bitmap file format. * * 

The decodeFromBitmap()-methods retrieve the orginal payload from a * previously encoded bitmap. A bitmap not encoded with this class cannot be read. * *

Example: * *

 * // Encode file "/etc/hosts" into file "/tmp/hosts.bmp", and restore it to "/tmp/hosts-restored" * BitmapEncoder.encodeToBitmap(new File("/etc/hosts"), new File("/tmp/hosts.bmp")); * BitmapEncoder.decodeFromBitmap(new File("/tmp/hosts.bmp"), new File("/tmp/hosts-restored")); * * // Encode 3 bytes into a bitmap file * BitmapEncoder.encodeToBitmap(new byte[] { 0x01, 0x02, 0x03 }, new File("/tmp/3- bytes.bmp")); * byte[] threebytes = BitmapEncoder.decodeFromBitmap(new File("/tmp/3-bytes.bmp")); * 

* * @author Philipp C. Heckel * @see http://blog.philippheckel.com/2013/03/02/java-encode-any-byte-array-stream-or-file-into-a-24-bit-bitmap-bmp/ */ public class BitmapEncoder { private static final int BMP_SIZE_HEADER= 54; // total header length, 54 bytes private static final int BMP_SIZE_IMAGE_WIDTH = 4; // size of image width field, 4 bytes private static final int BMP_SIZE_PAYLOAD_LENGTH = 4; // size of 'horizontal resolution' field, here: payload length, 4 bytes private static final int BMP_SIZE_BMPUTIL_MAGIC = 4; // size of 'vertical resolution' field, here: payload length, 4 bytes private static final int BMP_OFFSET_FILESIZE_BYTES = 2; // offset of filesize field, 4 bytes private static final int BMP_OFFSET_IMAGE_WIDTH = 18; // offset of image width field, 4 bytes private static final int BMP_OFFSET_IMAGE_HEIGHT = 22; // offset of image height field, 4 bytes private static final int BMP_OFFSET_IMAGE_DATA_BYTES = 34; // 4 bytes private static final int BMP_OFFSET_PAYLOAD_LENGTH = 38; // 4 bytes private static final int BMP_OFFSET_BMPUTIL_MAGIC = 42; // 4 bytes private static final byte UDEF = 0; // undefined value in bitmap header, to be overwritten by methods /** * 24-bit bitmap header * @see http://www.fastgraph.com/help/bmp_header_format.html */ private static final byte[] BMP_HEADER = new byte[] { /* 00 */ 0x42, 0x4d, // signature, "BM" /* 02 */ UDEF, UDEF, UDEF, UDEF, // size in bytes, filled dynamically /* 06 */ 0x00, 0x00, // reserved, must be zero /* 08 */ 0x00, 0x00, // reserved, must be zero /* 10 */ 0x36, 0x00, 0x00, 0x00, // offset to start of image data in bytes /* 14 */ 0x28, 0x00, 0x00, 0x00, // size of BITMAPINFOHEADER structure, must be 40 (0x28) /* 18 */ UDEF, UDEF, UDEF, UDEF, // image width in pixels, filled dynamically /* 22 */ UDEF, UDEF, UDEF, UDEF, // image height in pixels, filled dynamically /* 26 */ 0x01, 0x00, // number of planes, must be 1 /* 28 */ 0x18, 0x00, // number of bits per pixel (1, 4, 8, or 24) -> 24 = 0x18 /* 30 */ 0x00, 0x00, 0x00, 0x00, // compression type (0=none, 1=RLE-8, 2=RLE-4) /* 34 */ UDEF, UDEF, UDEF, UDEF, // size of image data in bytes (including padding) /* 38 */ UDEF, UDEF, UDEF, UDEF, // normally: horizontal resolution in pixels per meter (unreliable) // --> HERE: used to indicate the payload length /* 42 */ UDEF, UDEF, UDEF, UDEF, // vertical resolution in pixels per meter (unreliable) // --> HERE: used to mark file as encoded bitmap, see BMPUTIL_MAGIC /* 46 */ 0x00, 0x00, 0x00, 0x00, // number of colors in image, or zero /* 50 */ 0x00, 0x00, 0x00, 0x00, // number of important colors, or zero }; /** * Magic value to mark files created by this class */ private static final byte[] BMPUTIL_MAGIC = new byte[] { 0x30, 0x32, 0x30, 0x35 // mark used in 'vertical resolution' field to mark bmp file, "0205" }; /** * Encodes any File into a 24-bit bitmap (BMP) and outputs the image * to another File. * *

The method does not hide, encrypt or compress the source data in any * way. It merely prepends a bitmap header and transforms the payload as * specified by the bitmap file format. * * @param srcFile File to be read pointing to the input data (payload) * @param destFile File to write the 24-bit bitmap file to * @throws IOException Thrown if the input/output stream cannot be read/written */ public static void encodeToBitmap(File srcFile, File destFile) throws IOException { encodeToBitmap(new FileInputStream(srcFile), srcFile.length(), new FileOutputStream(destFile)); } /** * Encodes any File into a 24-bit bitmap (BMP) and outputs the image * to another File. * *

The method does not hide, encrypt or compress the source data in any * way. It merely prepends a bitmap header and transforms the payload as * specified by the bitmap file format. * * @param srcBytes Byte array of input data (payload) * @param destStream Stream to write the 24-bit bitmap file to * @throws IOException Thrown if the input/output stream cannot be read/written */ public static void encodeToBitmap(byte[] srcBytes, File destFile) throws IOException { encodeToBitmap(new ByteArrayInputStream(srcBytes), srcBytes.length, new FileOutputStream(destFile)); } /** * Encodes a byte array into a 24-bit bitmap (BMP) and outputs the image * to an OutputStream. * *

The method does not hide, encrypt or compress the source data in any * way. It merely prepends a bitmap header and transforms the payload as * specified by the bitmap file format. * * @param srcBytes Byte array of input data (payload) * @param destStream Stream to write the 24-bit bitmap file to * @throws IOException Thrown if the input/output stream cannot be read/written */ public static void encodeToBitmap(byte[] srcBytes, OutputStream destStream) throws IOException { encodeToBitmap(new ByteArrayInputStream(srcBytes), srcBytes.length, destStream); } /** * Encodes an InputStream into a 24-bit bitmap (BMP) and outputs the image * as byte array. * *

The method does not hide, encrypt or compress the source data in any * way. It merely prepends a bitmap header and transforms the payload as * specified by the bitmap file format. * * @param srcStream Stream of input data (payload) * @param srcStreamLength Length of the input data stream (in bytes) * @param destStream Stream to write the 24-bit bitmap file to * @throws IOException Thrown if the input/output stream cannot be read/written */ public static void encodeToBitmap(InputStream srcStream, long srcStreamLength, OutputStream destStream) throws IOException { if (srcStreamLength > Integer.MAX_VALUE) { throw new IOException("File too big; max. "+Integer.MAX_VALUE+" bytes supported."); } // CALCULATE HEADER FIELDS int imageWidth = (int) Math.ceil(Math.sqrt((double) srcStreamLength / 3)); / / Image width, sqrt(payload/3), divided by 3 because of RGB int imageHeight = (int) Math.ceil((double) srcStreamLength // Image height, payload / image width / 3 / (double) imageWidth / 3); int rowPadding = 4 - (imageWidth*3 % 4); // Padding at row end, row length must be divisible by 4 int filesizeBytes = imageWidth*imageHeight*3 + imageHeight*rowPadding // Total bitmap size, RGB-data + padding-data + header + BMP_SIZE_HEADER; int imageBytesWithPadding = filesizeBytes - BMP_SIZE_HEADER; // Image bytes without header (incl. padding), required field in header int payloadPadding = (int) (imageWidth*imageHeight*3 - srcStreamLength); // Padding at the end of the image, to make it rectangular // System.out.println("payloadLength = "+srcStreamLength); // System.out.println("imageWidth = sqrt(payloadLength/3) = "+imageWidth); // System.out.println("imageHeight = payloadLength / imageWidth / 3 = "+imageHeight); // System.out.println("rowPadding = "+rowPadding); // System.out.println("filesizeBytes = imageWidth*imageHeight*3 + imageHeight*rowPadding + BMP_SIZE_HEADER = "+filesizeBytes); // System.out.println("imageBytesWithPadding = filesizeBytes - BMP_SIZE_HEADER = "+imageBytesWithPadding); // System.out.println("payloadPadding = imageWidth*imageHeight*3 - payloadLength = "+payloadPadding); // WRITE FIELDS TO HEADER byte[] header = BMP_HEADER.clone(); // Clone bitmap header template, and overwrite with fields writeIntLE(header, BMP_OFFSET_FILESIZE_BYTES, filesizeBytes); writeIntLE(header, BMP_OFFSET_IMAGE_WIDTH, imageWidth); writeIntLE(header, BMP_OFFSET_IMAGE_HEIGHT, imageHeight); writeIntLE(header, BMP_OFFSET_IMAGE_DATA_BYTES, imageBytesWithPadding); writeIntLE(header, BMP_OFFSET_PAYLOAD_LENGTH, (int) srcStreamLength); System.arraycopy(BMPUTIL_MAGIC, 0, header, // Copy magic number to header BMP_OFFSET_BMPUTIL_MAGIC, BMPUTIL_MAGIC.length); // WRITE TO STREAM // Add payload destStream.write(header, 0, header.length); // Write other lines (regular width) byte[] row = new byte[imageWidth*3]; int read; while ((read = srcStream.read(row)) != -1) { destStream.write(row, 0, read); // Write payload destStream.write(new byte[rowPadding]); // Write padding } // Write payload padding destStream.write(new byte[payloadPadding]); srcStream.close(); destStream.close(); } /** * Decodes a 24-bit bitmap previously encoded by this class from * an InputStream to a byte array. * *

The method can only read bitmaps that were encoded using one of the * encodeToBitmap() methods. It will throw an exception if * any other bitmaps are read. * * @param srcStream Stream of input data (24-bit bitmap) * @return The original data read from the bitmap (payload) * @throws IOException Thrown if the input/output stream cannot be read/written */ public static byte[] decodeFromBitmap(InputStream srcStream) throws IOException { ByteArrayOutputStream destStream = new ByteArrayOutputStream(); decodeFromBitmap(srcStream, destStream); return destStream.toByteArray(); } /** * Decodes a 24-bit bitmap previously encoded by this class from * a File to a byte array. * *

The method can only read bitmaps that were encoded using one of the * encodeToBitmap() methods. It will throw an exception if * any other bitmaps are read. * * @param srcFile File to be read pointing to the input data (24-bit bitmap) * @return The original data read from the bitmap (payload) * @throws IOException Thrown if the input/output stream cannot be read/written */ public static byte[] decodeFromBitmap(File srcFile) throws IOException { ByteArrayOutputStream destStream = new ByteArrayOutputStream(); decodeFromBitmap(new FileInputStream(srcFile), destStream); return destStream.toByteArray(); } /** * Decodes a 24-bit bitmap previously encoded by this class from * a File to another File. * *

The method can only read bitmaps that were encoded using one of the * encodeToBitmap() methods. It will throw an exception if * any other bitmaps are read. * * @param srcFile File to be read pointing to the input data (24-bit bitmap) * @param destFile File to be written the original data to (payload) * @throws IOException Thrown if the input/output stream cannot be read/written */ public static void decodeFromBitmap(File srcFile, File destFile) throws IOException { decodeFromBitmap(new FileInputStream(srcFile), new FileOutputStream(destFile)); } /** * Decodes a 24-bit bitmap previously encoded by this class from * an InputStream to an OutputStream. * *

The method can only read bitmaps that were encoded using one of the * encodeToBitmap() methods. It will throw an exception if * any other bitmaps are read. * * @param srcStream Stream to be read pointing to the input data (24-bit bitmap) * @param destStream Stream to be written the original data to (payload) * @throws IOException Thrown if the input/output stream cannot be read/written */ public static void decodeFromBitmap(InputStream srcStream, OutputStream destStream) throws IOException { // READ HEADER long bytesRead = 0; // Skip ahead & read 'image width' field bytesRead += srcStream.skip(BMP_OFFSET_IMAGE_WIDTH - bytesRead); // Stores the image width, needed for row length and byte[] imageWidthBytes = new byte[BMP_SIZE_IMAGE_WIDTH]; // row padding calculation bytesRead += srcStream.read(imageWidthBytes); int imageWidth = toIntLE(imageWidthBytes); // Skip ahead & read 'horizontal resolution' field bytesRead += srcStream.skip(BMP_OFFSET_PAYLOAD_LENGTH - bytesRead); // Stores the payload length, needed for read-loop below byte[] payloadLengthBytes = new byte[BMP_SIZE_PAYLOAD_LENGTH]; bytesRead += srcStream.read(payloadLengthBytes); int payloadLength = toIntLE(payloadLengthBytes); // Skip ahead & read 'vertical resolution' field bytesRead += srcStream.skip(BMP_OFFSET_BMPUTIL_MAGIC - bytesRead); // Stores the magic field, needed to check if the image was byte[] magicFieldBytes = new byte[BMP_SIZE_BMPUTIL_MAGIC]; // previously encoded using this class bytesRead += srcStream.read(magicFieldBytes); if (!Arrays.equals(BMPUTIL_MAGIC, magicFieldBytes)) { throw new IOException("Given bitmap does not contain encoded binary data."); } // Skip ahead to the actual payload bytesRead += srcStream.skip(BMP_SIZE_HEADER - bytesRead); // Skip the rest of the header // READ PAYLOAD if (payloadLength > 0) { int rowPaddingLength = 4 - (imageWidth*3 % 4); // Padding at row end, row length must be divisible by 4 int rowLength = imageWidth*3; // Row width is 3x the image width (RGB coding) // System.out.println("payloadLength = "+payloadLength); // System.out.println("imageWidth = "+imageWidth); // System.out.println("rowPaddingLength = "+rowPaddingLength); // System.out.println("rowLength = "+rowLength); byte[] row = new byte[rowLength]; int read; int restOfPayload = payloadLength; while ((read = srcStream.read(row)) != -1) { if (restOfPayload >= read) { destStream.write(row, 0, read); // Write to output stream srcStream.skip(rowPaddingLength); // Skip bitmap padding (if any) restOfPayload -= read; } else { destStream.write(row, 0, restOfPayload); // Write the last bytes break; } } } srcStream.close(); destStream.close(); } /** * Write an integer to a byte array (as little endian) at a * specific offset. */ private static void writeIntLE(byte[] bytes, int startoffset, int value) { bytes[startoffset] = (byte)(value); bytes[startoffset+1] = (byte)(value >>> 8); bytes[startoffset+2] = (byte)(value >>> 16); bytes[startoffset+3] = (byte)(value >>> 24); } /** * Read an integer value from a 4-byte array (as little endian). */ private static int toIntLE(byte[] value) { return ((value[3] & 0xff) << 24) | ((value[2] & 0xff) << 16) | ((value[1] & 0xff) << 8) | (value[0] & 0xff); } /** * Encode/decode a bitmap from the command line. * *

Syntax:
* BitmapEncoder encode SRCFILE DESTFILE.bmp
*
BitmapEncoder decode SRCFILE.bmp DESTFILE */ public static void main(String[] args) throws IOException { if (args.length >= 2 && "encode".equals(args[0])) { BitmapEncoder.encodeToBitmap(new File(args[1]), new File(args[2])); } else if (args.length >= 2 && "decode".equals(args[0])) { BitmapEncoder.decodeFromBitmap(new File(args[1]), new File(args[2])); } else { System.out.println("Usage: BitmapEncoder encode SRCFILE DESTFILE.bmp"); System.out.println(" BitmapEncoder decode SRCFILE.bmp DESTFILE"); } } }