public static boolean equalsPixelData(File f1, File f2) throws IOException { InputStream in1 = new BufferedInputStream(new FileInputStream(f1)); try { InputStream in2 = new BufferedInputStream(new FileInputStream(f2)); try { Dataset attrs = DcmObjectFactory.getInstance().newDataset(); DcmParserFactory pf = DcmParserFactory.getInstance(); DcmParser p1 = pf.newDcmParser(in1); DcmParser p2 = pf.newDcmParser(in2); p1.setDcmHandler(attrs.getDcmHandler()); p1.parseDcmFile(FileFormat.DICOM_FILE, Tags.PixelData); p2.parseDcmFile(FileFormat.DICOM_FILE, Tags.PixelData); int samples = attrs.getInt(Tags.SamplesPerPixel, 1); int frames = attrs.getInt(Tags.NumberOfFrames, 1); int rows = attrs.getInt(Tags.Rows, 1); int columns = attrs.getInt(Tags.Columns, 1); int bitsAlloc = attrs.getInt(Tags.BitsAllocated, 8); int bitsStored = attrs.getInt(Tags.BitsStored, bitsAlloc); int frameLength = rows * columns * samples * bitsAlloc / 8; int pixelDataLength = frameLength * frames; if (pixelDataLength > p1.getReadLength() || pixelDataLength > p2.getReadLength()) { return false; } byte[] b1 = new byte[BUFFER_SIZE]; byte[] b2 = new byte[BUFFER_SIZE]; int[] mask = {0xff, 0xff}; int len, len2; if (bitsAlloc == 16 && bitsStored < 16) { mask[p1.getDcmDecodeParam().byteOrder == ByteOrder.LITTLE_ENDIAN ? 1 : 0] = 0xff >>> (16 - bitsStored); } int pos = 0; while (pos < pixelDataLength) { len = in1.read(b1, 0, Math.min(pixelDataLength - pos, BUFFER_SIZE)); if (len < 0) // EOF return false; int off = 0; while (off < len) { off += len2 = in2.read(b2, off, len - off); if (len2 < 0) // EOF return false; } for (int i = 0; i < len; i++, pos++) if (((b1[i] - b2[i]) & mask[pos & 1]) != 0) return false; } return true; } finally { in2.close(); } } finally { in1.close(); } }
public static void verifyMD5(File file, String originalMd5) throws Exception { log.info("M-READ file:" + file); MessageDigest md = MessageDigest.getInstance("MD5"); BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); DigestInputStream dis = new DigestInputStream(in, md); try { DcmParser parser = DcmParserFactory.getInstance().newDcmParser(dis); parser.parseDcmFile(FileFormat.DICOM_FILE, Tags.PixelData); if ((parser.getReadTag() & 0xFFFFFFFFL) >= Tags.PixelData) { if (parser.getReadLength() == -1) { while (parser.parseHeader() == Tags.Item) { readOut(parser.getInputStream(), parser.getReadLength()); } } readOut(parser.getInputStream(), parser.getReadLength()); parser.parseDataset(parser.getDcmDecodeParam(), -1); } } finally { try { dis.close(); } catch (IOException ignore) { } } byte[] md5 = md.digest(); if (!Arrays.equals(md5, MD5.toBytes(originalMd5))) { log.error( "MD5 for " + file.getAbsolutePath() + " is different that expected. Has the file been changed or corrupted?"); throw new IllegalStateException("MD5 mismatch"); } }
public static int maxDiffPixelData(File f1, File f2) throws IOException { int maxDiff = 0; InputStream in1 = new BufferedInputStream(new FileInputStream(f1)); try { InputStream in2 = new BufferedInputStream(new FileInputStream(f2)); try { DcmObjectFactory df = DcmObjectFactory.getInstance(); DcmParserFactory pf = DcmParserFactory.getInstance(); Dataset attrs1 = df.newDataset(); Dataset attrs2 = df.newDataset(); DcmParser p1 = pf.newDcmParser(in1); DcmParser p2 = pf.newDcmParser(in2); p1.setDcmHandler(attrs1.getDcmHandler()); p2.setDcmHandler(attrs2.getDcmHandler()); p1.parseDcmFile(FileFormat.DICOM_FILE, Tags.PixelData); p2.parseDcmFile(FileFormat.DICOM_FILE, Tags.PixelData); int samples = attrs1.getInt(Tags.SamplesPerPixel, 1); int frames = attrs1.getInt(Tags.NumberOfFrames, 1); int rows = attrs1.getInt(Tags.Rows, 1); int columns = attrs1.getInt(Tags.Columns, 1); int bitsAlloc = attrs1.getInt(Tags.BitsAllocated, 8); int bitsStored = attrs1.getInt(Tags.BitsStored, bitsAlloc); int bitsStored2 = attrs2.getInt(Tags.BitsStored, bitsAlloc); int pixelRepresentation1 = attrs1.getInt(Tags.PixelRepresentation, 0); int pixelRepresentation2 = attrs2.getInt(Tags.PixelRepresentation, 0); int frameLength = rows * columns * samples * bitsAlloc / 8; int pixelDataLength = frameLength * frames; if (pixelDataLength > p1.getReadLength() || pixelDataLength > p2.getReadLength()) { return Integer.MAX_VALUE; } byte[] b1 = new byte[BUFFER_SIZE]; byte[] b2 = new byte[BUFFER_SIZE]; byte lsb1 = 0, lsb2 = 0; int w1, w2, len, len2; int bitmask1 = 0xffff >>> (bitsAlloc - bitsStored); int bitmask2 = 0xffff >>> (bitsAlloc - bitsStored2); int signed1 = pixelRepresentation1 != 0 ? (-1 & ~bitmask1) >> 1 : 0; int signed2 = pixelRepresentation2 != 0 ? (-1 & ~bitmask2) >> 1 : 0; int pos = 0; while (pos < pixelDataLength) { len = in1.read(b1, 0, Math.min(pixelDataLength - pos, BUFFER_SIZE)); if (len < 0) // EOF return Integer.MAX_VALUE; int off = 0; while (off < len) { off += len2 = in2.read(b2, off, len - off); if (len2 < 0) // EOF return Integer.MAX_VALUE; } if (bitsAlloc == 8) for (int i = 0; i < len; i++, pos++) maxDiff = Math.max(maxDiff, Math.abs((b1[i] & 0xff) - (b2[i] & 0xff))); else { for (int i = 0; i < len; i++, pos++) // TODO assumes LE Byte Order if ((pos & 1) == 0) { lsb1 = b1[i]; lsb2 = b2[i]; } else { if (((w1 = ((b1[i] << 8) | (lsb1 & 0xff)) & bitmask1) & signed1) != 0) w1 |= signed1; if (((w2 = ((b2[i] << 8) | (lsb2 & 0xff)) & bitmask2) & signed2) != 0) w2 |= signed2; maxDiff = Math.max(maxDiff, Math.abs(w1 - w2)); } } } return maxDiff; } finally { in2.close(); } } finally { in1.close(); } }
/** * Convert an image to RGB. * * @param inFile the file to convert. * @param outFile the output file, which may be same as inFile. * @return the static status result */ public static AnonymizerStatus convert(File inFile, File outFile) { long fileLength = inFile.length(); logger.debug("Entering DICOMPaletteImageConverter.convert"); logger.debug("File length = " + fileLength); BufferedInputStream in = null; BufferedOutputStream out = null; File tempFile = null; byte[] buffer = new byte[4096]; try { // Check that this is a known format. in = new BufferedInputStream(new FileInputStream(inFile)); DcmParser parser = pFact.newDcmParser(in); FileFormat fileFormat = parser.detectFileFormat(); if (fileFormat == null) { throw new IOException("Unrecognized file format: " + inFile); } // Get the dataset (excluding pixels) and leave the input stream open Dataset dataset = oFact.newDataset(); parser.setDcmHandler(dataset.getDcmHandler()); parser.parseDcmFile(fileFormat, Tags.PixelData); // Make sure this is an image if (parser.getReadTag() != Tags.PixelData) { close(in); return AnonymizerStatus.SKIP(inFile, "Not an image"); } // Get the required parameters and make sure they are okay int numberOfFrames = getInt(dataset, Tags.NumberOfFrames, 1); int rows = getInt(dataset, Tags.Rows, 0); int columns = getInt(dataset, Tags.Columns, 0); String photometricInterpretation = getString(dataset, Tags.PhotometricInterpretation, ""); if ((rows == 0) || (columns == 0)) { close(in); return AnonymizerStatus.SKIP(inFile, "Unable to get the rows and columns"); } if (!photometricInterpretation.equals("PALETTE COLOR")) { close(in); return AnonymizerStatus.SKIP( inFile, "Unsupported PhotometricInterpretation: " + photometricInterpretation); } if (parser.getReadTag() != Tags.PixelData) { close(in); return AnonymizerStatus.SKIP(inFile, "No pixels"); } // Get the encoding and set the parameters DcmDecodeParam fileParam = parser.getDcmDecodeParam(); String fileEncodingUID = UIDs.ImplicitVRLittleEndian; FileMetaInfo fmi = dataset.getFileMetaInfo(); if (fmi != null) fileEncodingUID = fmi.getTransferSyntaxUID(); boolean isBigEndian = fileEncodingUID.equals(UIDs.ExplicitVRBigEndian); String encodingUID = UIDs.ExplicitVRLittleEndian; DcmEncodeParam encoding = (DcmEncodeParam) DcmDecodeParam.valueOf(encodingUID); boolean swap = (fileParam.byteOrder != encoding.byteOrder); if (encoding.encapsulated) { logger.debug("Encapsulated pixel data found"); close(in); return AnonymizerStatus.SKIP(inFile, "Encapsulated pixel data not supported"); } // Get the LUTs LUT red = new LUT( dataset.getInts(Tags.RedPaletteColorLUTDescriptor), dataset.getInts(Tags.RedPaletteColorLUTData)); LUT green = new LUT( dataset.getInts(Tags.GreenPaletteColorLUTDescriptor), dataset.getInts(Tags.GreenPaletteColorLUTData)); LUT blue = new LUT( dataset.getInts(Tags.BluePaletteColorLUTDescriptor), dataset.getInts(Tags.BluePaletteColorLUTData)); // Set the PlanarConfiguration to 0 dataset.putUS(Tags.PlanarConfiguration, 0); // Set the PhotometricInterpretation to RGB dataset.putCS(Tags.PhotometricInterpretation, "RGB"); // Set the pixel parameters dataset.putUS(Tags.SamplesPerPixel, 3); dataset.putUS(Tags.BitsAllocated, 8); dataset.putUS(Tags.BitsStored, 8); dataset.putUS(Tags.HighBit, 7); // Remove the lookup tables and their descriptors dataset.remove(Tags.RedPaletteColorLUTDescriptor); dataset.remove(Tags.GreenPaletteColorLUTDescriptor); dataset.remove(Tags.BluePaletteColorLUTDescriptor); dataset.remove(Tags.RedPaletteColorLUTData); dataset.remove(Tags.GreenPaletteColorLUTData); dataset.remove(Tags.BluePaletteColorLUTData); // Save the dataset to a temporary file, and rename at the end. File tempDir = outFile.getParentFile(); tempFile = File.createTempFile("DCMtemp-", ".anon", tempDir); out = new BufferedOutputStream(new FileOutputStream(tempFile)); // Create and write the metainfo for the encoding we are using fmi = oFact.newFileMetaInfo(dataset, encodingUID); dataset.setFileMetaInfo(fmi); fmi.write(out); // Write the dataset as far as was parsed dataset.writeDataset(out, encoding); // Process the pixels int nPixels = numberOfFrames * rows * columns; int nPixelBytes = nPixels * 3 /*samplesPerPixel*/; int pad = nPixelBytes & 1; dataset.writeHeader(out, encoding, parser.getReadTag(), VRs.OB, nPixelBytes + pad); int pd; int b1, b2; int bytesPerFrame = rows * columns * 2; byte[] frameBytes = new byte[bytesPerFrame]; for (int frame = 0; frame < numberOfFrames; frame++) { if (in.read(frameBytes, 0, frameBytes.length) != bytesPerFrame) throw new Exception("End of File"); for (int p = 0; p < bytesPerFrame; ) { b1 = frameBytes[p++]; b2 = frameBytes[p++]; if (!swap) { pd = ((b2 & 0xff) << 8) | (b1 & 0xff); } else { pd = ((b1 & 0xff) << 8) | (b2 & 0xff); } out.write(red.get(pd)); out.write(green.get(pd)); out.write(blue.get(pd)); } } if (pad != 0) out.write(0); logger.debug("Finished writing the pixels"); // Skip everything after the pixels out.flush(); out.close(); in.close(); outFile.delete(); tempFile.renameTo(outFile); return AnonymizerStatus.OK(outFile, ""); } catch (Exception e) { logger.debug("Exception while processing image.", e); // Close the input stream if it actually got opened. close(in); // Close the output stream if it actually got opened, // and delete the tempFile in case it is still there. try { if (out != null) { out.close(); tempFile.delete(); } } catch (Exception ex) { logger.warn("Unable to close the output stream."); } // Quarantine the object return AnonymizerStatus.QUARANTINE(inFile, e.getMessage()); } }