public static byte[] getUncrushedPNGBytes(ProcessedPNG png) throws Exception {
		boolean foundIHDR = false;
		boolean foundIDAT = false;
		boolean foundCgBI = false;
		IHDRChunk ihdrChunk = null;
		byte[] repackArray = null;
		List<PNGChunk> wantedChunks = new ArrayList<>();
		ByteArrayOutputStream idatStream = new ByteArrayOutputStream();

		for (PNGChunk chunk : png.getChunkArray()) {
			byte[] idBytes = chunk.getChunkIDBytes();

			//Ignore the inserted CgBI chunk
			if (!(Arrays.equals(idBytes, CrushedPNGConstants.INSERTED_IOS_CHUNK))) {
				if (Arrays.equals(idBytes, CrushedPNGConstants.IHDR_CHUNK)) {
					//Msg.debug(this, "Found IHDR Chunk");

					foundIHDR = true;
					ihdrChunk = new IHDRChunk(chunk);
					wantedChunks.add(chunk);
					byte[] checksum = calculateCRC32(chunk);
					if (!Arrays.equals(checksum, chunk.getCrc32Bytes())) {
						throw new PNGFormatException("Bad CRC32 on " + chunk.getChunkID() +
							" chunk");
					}

				}

				//All Other chunks. Look for the IDAT Chunks to fix RGB(A) values
				else if (Arrays.equals(idBytes, CrushedPNGConstants.IDAT_CHUNK)) {
					//Msg.debug(this, "Found IDAT Chunk");

					idatStream.write(chunk.getData());
					wantedChunks.add(chunk);
					foundIDAT = true;
					byte[] checksum = calculateCRC32(chunk);
					if (!Arrays.equals(checksum, chunk.getCrc32Bytes())) {
						throw new PNGFormatException("Bad CRC32 on " + chunk.getChunkID() +
							" chunk");
					}

				}
				else {
					//Msg.debug(this, "Found " + chunk.getIDString() + " Chunk");

					wantedChunks.add(chunk);
					byte[] checksum = calculateCRC32(chunk);
					if (!Arrays.equals(checksum, chunk.getCrc32Bytes())) {
						throw new PNGFormatException("Bad CRC32 on " + chunk.getChunkID() +
							" chunk");
					}

				}
			}
			else {
				foundCgBI = true;
			}
		}

		if (!foundIHDR) {
			throw new PNGFormatException("Missing IHDR Chunk");
		}
		if (!foundIDAT) {
			throw new PNGFormatException("Missing IDAT chunk(s)");
		}
		if (!foundCgBI) {
			throw new PNGFormatException("Missing CgBI chunk. PNG is not in crushed format");
		}
		if (ihdrChunk == null) {
			throw new PNGFormatException("Invalid IHDRChunk found to be null");
		}

		//Process the IDAT chunks
		if (ihdrChunk.getBitDepth() == 8 && ihdrChunk.getColorType() == 2 ||
			ihdrChunk.getColorType() == 6) {

			int expectedSize =
				(ihdrChunk.getBytesPerLine() * ihdrChunk.getImgHeight()) +
					ihdrChunk.getRowFilterBytes();
			byte[] results;
			try (ByteArrayOutputStream decompressedOutput = new ByteArrayOutputStream(expectedSize);
				InflaterOutputStream inflaterStream = new InflaterOutputStream(decompressedOutput)) {

				inflaterStream.write(ZLIB.ZLIB_COMPRESSION_DEFAULT);
				idatStream.writeTo(inflaterStream);
				inflaterStream.finish();
				results = decompressedOutput.toByteArray();
			}
			if (results.length != expectedSize) {
				throw new PNGFormatException("Decompression Error, expected " + expectedSize +
					" bytes, but got " + results.length + " bytes");
			}

			//Processes the IDAT chunks to 'uncrushify' them
			processIDATChunks(ihdrChunk, results);

			try (ByteArrayOutputStream compressedOutput = new ByteArrayOutputStream(CrushedPNGConstants.INITIAL_REPACK_SIZE);
				DeflaterOutputStream deflaterStream = new DeflaterOutputStream(compressedOutput)) {

				deflaterStream.write(results);
				deflaterStream.finish();
				deflaterStream.flush();
				repackArray = compressedOutput.toByteArray();
			}
		}

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		outputStream.write(CrushedPNGConstants.SIGNATURE_BYTES);

		//Rebuild the new PNG useing the origional chunks and replacing the old crushed IDAT chunks
		boolean wroteIDAT = false;
		for (PNGChunk chunk : png.getChunkArray()) {
			byte[] idBytes = chunk.getChunkIDBytes();
			if (!(Arrays.equals(idBytes, CrushedPNGConstants.INSERTED_IOS_CHUNK))) {

				//If the chunk is the old IDAT chunk replace with new IDAT data
				if ((repackArray != null) && Arrays.equals(idBytes, CrushedPNGConstants.IDAT_CHUNK)) {
					if (!wroteIDAT) {
						//Write the chunk data length
						int dataLength = repackArray.length;
						byte[] lengthBytes = ByteBuffer.allocate(4).putInt(dataLength).array();
						outputStream.write(lengthBytes);

						//Gather ID and data together to calculate CRC32
						byte[] idat = new byte[CrushedPNGConstants.IDAT_CHUNK.length + dataLength];
						for (int i = 0; i < CrushedPNGConstants.IDAT_CHUNK.length; i++) {
							idat[i] = CrushedPNGConstants.IDAT_CHUNK[i];
						}
						for (int i = 0; i < dataLength; i++) {
							idat[CrushedPNGConstants.IDAT_CHUNK.length + i] = repackArray[i];
						}

						//Write the chunk data
						outputStream.write(idat);

						//Calculate and write chunk crc32
						byte[] checksum = calculateCRC32(idat);
						outputStream.write(checksum);

						wroteIDAT = true;
					}
				}
				else {

					//For any other wanted chunks other than IDAT insert them back in
					//Write the chunk data length
					outputStream.write(chunk.getLengthBytes());

					//Write the chunk ID
					outputStream.write(idBytes);

					//Write the chunk data
					outputStream.write(chunk.getData());

					//Calculate and write CRC32
					//outputStream.write(chunk.getCrc32());
					byte[] checksum = calculateCRC32(chunk);
					outputStream.write(checksum);
				}
			}

		}

		return outputStream.toByteArray();
	}
Returns the converted bytes of the CrushedPNG to now represent
the structure and formatting of a normal non-crushed PNG.
@param png the CrushedPNG object
@return An InputStream of the correctly formated bytes of a png
@throws Exception
Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/png/CrushedPNGUtil.java