Why the image is not displayed in the imageItem? - java

I used the Nokia sample codes for Google Map. It has retrieveStaticImage method which loads and returns an Image. I them loaded the image to an ImageItem but I get an exception everytime..
Here are my codes...
Codes for GoogleMaps class
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.ImageItem;
public class GoogleMaps implements Runnable{
private static final String URL_UNRESERVED =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789-_.~";
private static final char[] HEX = "0123456789ABCDEF".toCharArray();
Image image;
int width;
int height;
double lat;
double lng;
int zoom;
String format;
ImageItem imagecmpt;
// these 2 properties will be used with map scrolling methods. You can remove them if not needed
public static final int offset = 268435456;
public static final double radius = offset / Math.PI;
private String apiKey = null;
public GoogleMaps(String key,int width, int height, double lat, double lng, int zoom,
String format,ImageItem img) {
this.width=width;
this.height=height;
this.lat=lat;
this.lng=lng;
this.zoom=zoom;
this.format=format;
apiKey = key;
}
public double[] geocodeAddress(String address) throws Exception {
byte[] res = loadHttpFile(getGeocodeUrl(address));
String[] data = split(new String(res), ',');
if (!data[0].equals("200")) {
int errorCode = Integer.parseInt(data[0]);
throw new Exception("Google Maps Exception: " + getGeocodeError(errorCode));
}
return new double[] {
Double.parseDouble(data[2]), Double.parseDouble(data[3])
};
}
public Image retrieveStaticImage() throws IOException {
byte[] imageData = loadHttpFile(getMapUrl(width, height, lng, lat, zoom, format));
System.out.println("Address is "+getMapUrl(width, height, lng, lat, zoom, format));
for (int i=0;i<imageData.length;i++){
System.out.println(imageData[i]);
}
return Image.createImage(imageData, 0, imageData.length);
}
private static String getGeocodeError(int errorCode) {
switch (errorCode) {
case 400:
return "Bad request";
case 500:
return "Server error";
case 601:
return "Missing query";
case 602:
return "Unknown address";
case 603:
return "Unavailable address";
case 604:
return "Unknown directions";
case 610:
return "Bad API key";
case 620:
return "Too many queries";
default:
return "Generic error";
}
}
private String getGeocodeUrl(String address) {
return "http://maps.google.com/maps/geo?q=" + urlEncode(address) + "&output=csv&key="
+ apiKey;
}
private String getMapUrl(int width, int height, double lng, double lat, int zoom, String format) {
return "http://maps.google.com/staticmap?center=" + lat + "," + lng + "&format="
+ format + "&zoom=" + zoom + "&size=" + width + "x" + height + "&key=" + apiKey;
}
private static String urlEncode(String str) {
StringBuffer buf = new StringBuffer();
byte[] bytes = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF(str);
bytes = bos.toByteArray();
} catch (IOException e) {
// ignore
}
for (int i = 2; i < bytes.length; i++) {
byte b = bytes[i];
if (URL_UNRESERVED.indexOf(b) >= 0) {
buf.append((char) b);
} else {
buf.append('%').append(HEX[(b >> 4) & 0x0f]).append(HEX[b & 0x0f]);
}
}
return buf.toString();
}
private static byte[] loadHttpFile(String url) throws IOException {
byte[] byteBuffer;
HttpConnection hc = (HttpConnection) Connector.open(url);
try {
hc.setRequestMethod(HttpConnection.GET);
InputStream is = hc.openInputStream();
try {
int len = (int) hc.getLength();
if (len > 0) {
byteBuffer = new byte[len];
int done = 0;
while (done < len) {
done += is.read(byteBuffer, done, len - done);
}
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[512];
int count;
while ( (count = is.read(buffer)) >= 0 ) {
bos.write(buffer, 0, count);
}
byteBuffer = bos.toByteArray();
}
} finally {
is.close();
}
} finally {
hc.close();
}
return byteBuffer;
}
private static String[] split(String s, int chr) {
Vector res = new Vector();
int curr;
int prev = 0;
while ( (curr = s.indexOf(chr, prev)) >= 0 ) {
res.addElement(s.substring(prev, curr));
prev = curr + 1;
}
res.addElement(s.substring(prev));
String[] splitted = new String[res.size()];
res.copyInto(splitted);
return splitted;
}
public void run() {
try{
//throw new UnsupportedOperationException("Not supported yet.");
imagecmpt.setImage(retrieveStaticImage());
}
catch(Exception e){
System.out.println("Error ......."+e);
}
}
}
code for midlet
public void commandAction(Command command, Displayable displayable) {
// write pre-action user code here
if (displayable == form) {
if (command == exitCommand) {
// write pre-action user code here
exitMIDlet();
// write post-action user code here
} else if (command == okCommand) {
// write pre-action user code here
// write post-action user code here
GoogleMaps cMz=new GoogleMaps("ABQIAAAADEQoVqbqS5pT4ahHSLALyBT8PMUw5z7_OLJoE1lh2VQyfb-WOxTwS9t9mrSq_flhdPeVGOQrxXuCFQ",10, 10, 10, 10, 1, "roadmap", imageItem);
Thread th=new Thread(cMz);
th.run();
Display display=getDisplay ();
}
}
// write post-action user code here
}
My output:::
Starting emulator in execution mode
Running with storage root DefaultColorPhone
Running with locale: English_United States.1252
Running in the identified_third_party security domain
Warning: To avoid potential deadlock, operations that may block, such as
networking, should be performed in a different thread than the
commandAction() handler.
I have used an external thread but yet it keeps telling me to use another thread..
How can I sort this out?

Try
new Thread(new Runnable(){
GoogleMaps cMz=new GoogleMaps("ABQIAAAADEQoVqbqS5pT4ahHSLALyBT8PMUw5z7_OLJoE1lh2VQyfb-WOxTwS9t9mrSq_flhdPeVGOQrxXuCFQ",10, 10, 10, 10, 1, "roadmap", imageItem);
//put here action
}
).start();

Related

How to store an ArrayList in a file?

I have a class which represents an ArrayList stored in a file, because I need an ArrayList with multiple gigabytes of data in it which is obviously too large to be stored in memory. The data is represented by a class called Field and the function Field.parse() is just for converting the Field into a String and the other way.
The Field class stores a list of (strange) chess pieces and their coordinates.
My class is working fine, but it takes a long time to add an element to the file and I need my program to run as fast as possible. Does anyone know a more efficient/faster way of doing things?
Also, I am not allowed to use external libraries/apis. Please keep that in mind.
This is the class which is responsible for storing Field objects in a temp file:
private File file;
private BufferedReader reader;
private BufferedWriter writer;
public FieldSaver() {
try {
file = File.createTempFile("chess-moves-", ".temp");
System.out.println(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
public void add(Field field) {
try {
File temp = File.createTempFile("chess-moves-", ".temp");
writer = new BufferedWriter(new FileWriter(temp));
reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null ) {
writer.write(line);
writer.newLine();
}
reader.close();
writer.write(field.parse());
writer.close();
file.delete();
file = new File(temp.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
public Field get(int n) {
try {
reader = new BufferedReader(new FileReader(file));
for (int i = 0; i < n; i++) {
reader.readLine();
}
String line = reader.readLine();
reader.close();
return Field.parse(line);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
And this is the Field class:
private WildBoar wildBoar;
private HuntingDog[] huntingDogs;
private Hunter hunter;
private int size;
#Override
public String toString() {
String result = "Wildschwein: " + wildBoar.toString();
for (HuntingDog dog : huntingDogs) {
result += "; Hund: " + dog.toString();
}
return result + "; Jäger: " + hunter.toString();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Field) {
Field field = (Field) obj;
HuntingDog[] dogs = field.getHuntingDogs();
return wildBoar.equals(field.getWildBoar()) && hunter.equals(field.getHunter()) && huntingDogs[0].equals(dogs[0]) && huntingDogs[1].equals(dogs[1]) && huntingDogs[2].equals(dogs[2]);
}
return false;
}
public Field(int size, WildBoar wildBoar, HuntingDog[] huntingDogs, Hunter hunter) {
this.size = size;
this.wildBoar = wildBoar;
this.huntingDogs = huntingDogs;
this.hunter = hunter;
}
public WildBoar getWildBoar() {
return wildBoar;
}
public HuntingDog[] getHuntingDogs() {
return huntingDogs;
}
public Hunter getHunter() {
return hunter;
}
public int getSize() {
return size;
}
public static Field parse(String s) {
String[] arr = s.split(",");
WildBoar boar = WildBoar.parse(arr[0]);
Hunter hunter = Hunter.parse(arr[1]);
HuntingDog[] dogs = new HuntingDog[arr.length - 2];
for(int i = 2; i < arr.length; i++) {
dogs[i - 2] = HuntingDog.parse(arr[i]);
}
return new Field(8, boar, dogs, hunter);
}
public String parse() {
String result = wildBoar.parse() + "," + hunter.parse();
for(HuntingDog dog : huntingDogs) {
result += "," + dog.parse();
}
return result;
}
Here's an MCVE to do what you want, based on the information you provided.
You can run it and see that it can save a Field to the file and get a Field by index very quickly.
The Fields are constant length, so you can get a Field by index by going to byte offset of index times field length in bytes. This would be significantly more difficult if the field were not constant length.
import java.io.Closeable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FieldSaver implements Closeable {
public static void main(String[] args) throws IOException {
File f = File.createTempFile("chess-moves-", ".temp");
try (FieldSaver test = new FieldSaver(f);) {
for (byte i = 0; i < 100; i++) {
test.add(new Field(8, new WildBoar(i, i), new Hunter(i, i), new HuntingDog[] {
new HuntingDog(i, i),
new HuntingDog(i, i),
new HuntingDog(i, i) }));
}
// Get a few Fields by index
System.out.println(test.get(0));
System.out.println(test.get(50));
System.out.println(test.get(99));
// EOF exception, there is no Field 100
// System.out.println(test.get(100));
}
}
private final RandomAccessFile data;
public FieldSaver(File f) throws FileNotFoundException {
data = new RandomAccessFile(f, "rw");
}
public void add(Field field) throws IOException {
data.seek(data.length());
field.write(data);
}
public Field get(int index) throws IOException {
data.seek(index * Field.STORAGE_LENGTH_BYTES);
return Field.read(data);
}
public void close() throws IOException { data.close(); }
static abstract class Piece {
protected byte xPos;
protected byte yPos;
public Piece(DataInput data) throws IOException {
xPos = data.readByte();
yPos = data.readByte();
}
public Piece(byte xPos, byte yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
public void write(DataOutput data) throws IOException {
data.writeByte(xPos);
data.writeByte(yPos);
}
public String toString() { return "[" + xPos + ", " + yPos + "]"; }
}
static class Hunter extends Piece {
public Hunter(byte xPos, byte yPos) { super(xPos, yPos); }
public Hunter(DataInput data) throws IOException { super(data); }
}
static class HuntingDog extends Piece {
public HuntingDog(byte xPos, byte yPos) { super(xPos, yPos); }
public HuntingDog(DataInput data) throws IOException { super(data); }
}
static class WildBoar extends Piece {
public WildBoar(byte xPos, byte yPos) { super(xPos, yPos); }
public WildBoar(DataInput data) throws IOException { super(data); }
}
static class Field {
// size of boar + hunter + 3 dogs
public static final int STORAGE_LENGTH_BYTES = 2 + 2 + (3 * 2);
private int size;
private WildBoar boar;
private Hunter hunter;
private final HuntingDog[] dogs;
public Field(int size, WildBoar wildBoar, Hunter hunter, HuntingDog[] huntingDogs) {
this.size = size;
this.boar = wildBoar;
this.hunter = hunter;
this.dogs = huntingDogs;
}
public String toString() {
String result = "Wildschwein: " + boar.toString();
for (HuntingDog dog : dogs) {
result += "; Hund: " + dog.toString();
}
return result + "; Jäger: " + hunter.toString();
}
public static Field read(DataInput data) throws IOException {
WildBoar boar = new WildBoar(data);
Hunter hunter = new Hunter(data);
HuntingDog[] dogs = new HuntingDog[3];
for (int i = 0; i < 3; i++) {
dogs[i] = new HuntingDog(data);
}
return new Field(8, boar, hunter, dogs);
}
public void write(DataOutput data) throws IOException {
boar.write(data);
hunter.write(data);
for (HuntingDog dog : dogs) {
dog.write(data);
}
}
}
}
Use a Map implementation like Cache from ehcache. This library will optimize for you so you don't have to handle writing and reading to disk and manage when to keep it in memory or on disk. You can just use it as a normal map. You probably want a map instead of a list for faster lookup so the library can optimize even more for you.
http://www.ehcache.org/
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.build())
.build(true);
Cache<Long, String> preConfigured
= cacheManager.getCache("preConfigured", Long.class, String.class);

Android adding AAC ADTS to Mediarecorder PCM

My Mediarecorder gives me a PCM File as an output when I record the phone's microphone. Now when trying to listen to this File that it created all I hear is static and I think, if I have understood correctly, I get a PCM file from Mediarecorder not AAC and I need to add ADTS header to the PCM to be able to listen to it.
I have seen threads with custom Encoders but I can not seem to figure out where and what I need to do with them.
I make an output File from microphone recoridng like this:
private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;
private static final int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private static final int SAMPLE_RATE = 44100; //44.1kHz
private static final int BUFFER_SIZE = 2048;
public Status status = Status.IDLE;
private AudioRecordingHandler arh;
private File outputFile;
private Context context;
/**
* Starts script for running. Needs output file to work!
*/
public void start() {
if (outputFile == null) { return; }
System.out.println("Start reading stream...");
aacEncoder = new AACEncoder(SAMPLE_RATE, micOutputPCM);
new Thread(new Runnable() {
#Override
public void run() {
record.startRecording();
byte[] data = new byte[BUFFER_SIZE];
float[] audioFloatBuffer = new float[BUFFER_SIZE/2];
Yin y = new Yin(SAMPLE_RATE, BUFFER_SIZE/2);
while(status == Status.RECORDING) {
record.read(data, 0, BUFFER_SIZE);
audioFloatBuffer = ConverterUtil.toFloatArray(data, 0, audioFloatBuffer,
0, audioFloatBuffer.length);
PitchDetectionResult pdr = y.getPitch(audioFloatBuffer);
aacEncoder.writeIntoOutputfile(data);
arh.handlePitch(pdr.getPitch());
}
aacEncoder.stopEncoding();
}
}).start();
}
/**
* Stops script
*/
public void stop() {
status = Status.IDLE;
record.stop();
arh.finishedRecording(micOutputPCM);
}
Here is how I get the byte[] from the File and where I try to encode the ADTS header to them.
public static File addHeaderToAac(File micOutputPCM, File output) throws IOException {
byte[] pcmFile = fullyReadFileToBytes(micOutputPCM);
int bufferSize = 2048;
//addADTSHeader to byte[] and return a File object
return fileWithADTSHeader;
}
public static byte[] fullyReadFileToBytes(File f) throws IOException {
int size = (int) f.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis= new FileInputStream(f);;
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e){
throw e;
} finally {
fis.close();
}
return bytes;
}
My question is, does anyone have an Encoder that can accept a File or byte[] or ByteStream as an input and return a File.
Because ultimately I want to make a mp4parser AACTrackImpl, which can be found here : https://github.com/sannies/mp4parser
AACTrackImpl aacTrack2 = new MP3TrackImpl(new FileDataSourceImpl(micOutputPCM));
Also If I am missing some important details about how to convert and what I should do to be able to play it then that information will also be useful.
If I need provide more information in order to answer this question, then I will gladly do so.
Edit:
I've been trying to make an encoder that would do what I need, but so far I have had no success.
public static File addHeaderToAac(File pcmFile1, File output, Context context) throws IOException {
byte[] pcmFile = fullyReadFileToBytes(pcmFile1);
int bufferSize = 2048;
AACEncoder encoder = new AACEncoder(44100, output);
encoder.encodeAudioFrameToAAC(pcmFile);
return output;
}
I am trying to encode the PCM to AAC with this encoder, but this encoder writes the output file to memory, but I need an object. And when I give it my byte[] it also gives me an error :
W/System.err: at java.nio.ByteBuffer.put(ByteBuffer.java:642)
And the error is coming from this line :
inputBuf.put(frameData);
Finally, my encoder:
public class AACEncoder {
final String TAG = "UEncoder Processor";
final int sampleRate;
File outputFile;
FileOutputStream fos;
final int TIMEOUT_USEC = 10000 ;
MediaCodec encoder;
boolean isEncoderRunning = false;
boolean outputDone = false;
MediaCodec.BufferInfo info;
public AACEncoder(final int sampleRate, File outputFile) {
this.sampleRate = sampleRate;
this.info = new MediaCodec.BufferInfo();
this.outputFile = outputFile;
openFileStream();
initEncoder();
}
/**
* Initializes CrappyEncoder for AAC-LC (Low complexity)
* #throws Exception
*/
public void initEncoder() {
try {
encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);
format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (IOException ex) {
Log.e(TAG, "Failed to create CrappyEncoder");
ex.printStackTrace();
}
}
int generateIndex = 0;
public void encodeAudioFrameToAAC(byte[] frameData) {
if (encoder == null) return;
if (!isEncoderRunning) {
encoder.start();
isEncoderRunning = true;
}
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
if (fos != null) {
int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
long ptsUsec = (System.currentTimeMillis() * 1000) / 10000;
if (outputDone) {
encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec,
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];
inputBuf.clear();
inputBuf.put(frameData);
encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);
}
generateIndex++;
}
tryEncodeOutputBuffer();
}
checkIfOutputDone();
}
/**
* Gets data from output buffer and encodes it to
* AAC-LC encoding with ADTS header attached before every frame
*/
private void tryEncodeOutputBuffer() {
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
//If >= 0 then valid response
int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
if (encoderStatus >= 0) {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
encodedData.position(info.offset);
encodedData.limit(info.offset + info.size + 7);
byte[] data = new byte[info.size + 7];
addADTStoPacket(data, info.size + 7);
encodedData.get(data, 7, info.size);
encodedData.position(info.offset);
writeIntoOutputfile(data);
encoder.releaseOutputBuffer(encoderStatus, false);
}
}
private void checkIfOutputDone() {
if (outputDone) {
if (fos != null) {
try {
fos.close();
} catch (IOException ioe) {
Log.w(TAG, "failed closing debug file");
throw new RuntimeException(ioe);
}
fos = null;
}
}
}
/**
* Add ADTS header at the beginning of each and every AAC packet.
* This is needed as MediaCodec CrappyEncoder generates a packet of raw
* AAC data.
*
* Note the packetLen must count in the ADTS header itself.
**/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; //AAC LC
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
int freqIdx = 4; //44.1KHz
int chanCfg = 2; //CPE
// fill in ADTS data
packet[0] = (byte)0xFF;
packet[1] = (byte)0xF9;
packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
packet[4] = (byte)((packetLen&0x7FF) >> 3);
packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
packet[6] = (byte)0xFC;
}
private void openFileStream() {
fos = null;
try {
fos = new FileOutputStream(outputFile, false);
} catch (FileNotFoundException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
/**
* Writes data into file
* #param data
*/
public void writeIntoOutputfile(byte[] data) {
try {
fos.write(data);
} catch (IOException ioe) {
Log.w(TAG, "failed writing debug data to file");
throw new RuntimeException(ioe);
}
}
public void stopEncoding() {
isEncoderRunning = false;
encoder.stop();
closeStream();
}
private void closeStream() {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
}

Java Compression & Decompression byte[] Chunks

like the JDK Deflater/Inflater classes that allows to pass byte[] chunks and get the compressed/uncompressed value as a byte[] chunk also (No need for Input or Output Streams), does anyone know of a way to do the same but for Zip files?
The idea is to be able to read an input stream by chunks and do a kind of transformation pipeline:
- Inbound: Encrypt and compress
- Outbound: Decrypt and decompress
With the ZipInput/OutputStream classes in order to do that I need to save all the bytes before encrypting/decrypting.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class Compression {
public static void main(String[] args) throws IOException, DataFormatException {
final int bufferSize = 1024;
byte[] uncompressedChunkBuffer = new byte[bufferSize];
int uncompressedChunkLength = 0;
byte[] compressedChunkBuffer = new byte[bufferSize];
int compressedChunkLength = 0;
//Compression
Deflater deflater = new Deflater();
String uncompressedText = randomText();
byte[] expectedUncompressedBytes = uncompressedText.getBytes();
System.out.println("Bytes Length: " + expectedUncompressedBytes.length);
ByteArrayInputStream uncompressedBytesInStream = new ByteArrayInputStream(expectedUncompressedBytes);
ByteArrayOutputStream compressedBytesOutStream = new ByteArrayOutputStream();
while ((uncompressedChunkLength = uncompressedBytesInStream.read(uncompressedChunkBuffer)) != -1) {
//This part allows to set and get byte[] chunks
deflater.setInput(uncompressedChunkBuffer, 0, uncompressedChunkLength);
while (!deflater.needsInput()) {
compressedChunkLength = deflater.deflate(compressedChunkBuffer);
if (compressedChunkLength > 0) {
compressedBytesOutStream.write(compressedChunkBuffer, 0, compressedChunkLength);
}
}
}
deflater.finish();
while (!deflater.finished()) {
compressedChunkLength = deflater.deflate(compressedChunkBuffer);
if (compressedChunkLength > 0) {
compressedBytesOutStream.write(compressedChunkBuffer, 0, compressedChunkLength);
}
}
deflater.end();
uncompressedBytesInStream.close();
compressedBytesOutStream.flush();
compressedBytesOutStream.close();
byte[] compressedBytes = compressedBytesOutStream.toByteArray();
System.out.println("Compressed Bytes Length: " + compressedBytes.length);
//Decompression
Inflater inflater = new Inflater();
ByteArrayInputStream compressedBytesInStream = new ByteArrayInputStream(compressedBytes);
ByteArrayOutputStream uncompressedBytesOutStream = new ByteArrayOutputStream();
while ((compressedChunkLength = compressedBytesInStream.read(compressedChunkBuffer)) != -1) {
//This part allows to set and get byte[] chunks
inflater.setInput(compressedChunkBuffer, 0, compressedChunkLength);
while ((uncompressedChunkLength = inflater.inflate(uncompressedChunkBuffer)) > 0) {
uncompressedBytesOutStream.write(uncompressedChunkBuffer, 0, uncompressedChunkLength);
}
}
while ((uncompressedChunkLength = inflater.inflate(uncompressedChunkBuffer)) > 0) {
uncompressedBytesOutStream.write(uncompressedChunkBuffer, 0, uncompressedChunkLength);
}
inflater.end();
compressedBytesInStream.close();
uncompressedBytesOutStream.flush();
uncompressedBytesOutStream.close();
byte[] actualUncompressedBytes = uncompressedBytesOutStream.toByteArray();
System.out.println("Uncompressed Bytes Length: Expected[" + expectedUncompressedBytes.length + "], Actual [" + actualUncompressedBytes.length + "]");
}
public static String randomText() {
StringBuilder sb = new StringBuilder();
int textLength = rnd(100, 999);
for (int i = 0; i < textLength; i++) {
if (rnd(0, 1) == 0) {
sb.append((char) rnd(65, 90));
} else {
sb.append((char) rnd(49, 57));
}
}
return sb.toString();
}
public static int rnd(int min, int max) {
return min + (int) (Math.random() * ((max - min) + 1));
}
}
Thanks to #rob suggestion I finally reached a solution:
private static final String SECRET_KEY_ALGO = "AES";
private static final int SECRET_KEY_SIZE_IN_BITS = 256;
private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final int DEFAULT_BUFFERSIZE = 8 * 1024;
public static void main(String[] args) throws IOException {
String expected = randomText();
byte[] textBytes = expected.getBytes();
EncryptedOutputStreamWrapper enc = new EncryptedOutputStreamWrapper();
{
InputStream in = new ByteArrayInputStream(textBytes);
ZipOutputStream out = new ZipOutputStream(enc.wrap(new FileOutputStream("f.zip")));
out.putNextEntry(new ZipEntry("_"));
IOUtils.copy(in, out);
in.close();
out.closeEntry();
out.close();
}
//
DecryptedInputStreamWrapper dec = new DecryptedInputStreamWrapper(enc.getSKey(), enc.getIv());
{
ZipInputStream in = new ZipInputStream(dec.wrap(new FileInputStream("f.zip")));
OutputStream out = new FileOutputStream("f.txt");
in.getNextEntry();
IOUtils.copy(in, out);
in.closeEntry();
in.close();
out.close();
}
//
String actual = new String(IOUtils.toByteArray(new FileInputStream("f.txt")));
if (!expected.equals(actual)) {
System.out.println("Fail!");
System.out.println("Expected '" + expected + "'");
System.out.println();
System.out.println("Actual: '" + actual + "'");
} else {
System.out.println("Success!");
}
}
public static class EncryptedOutputStreamWrapper {
private Cipher cipher;
private SecretKey sKey;
private byte[] iv;
public EncryptedOutputStreamWrapper() {
try {
KeyGenerator generator = KeyGenerator.getInstance(SECRET_KEY_ALGO);
generator.init(SECRET_KEY_SIZE_IN_BITS);
this.sKey = generator.generateKey();
this.cipher = Cipher.getInstance(AES_TRANSFORMATION);
this.cipher.init(Cipher.ENCRYPT_MODE, sKey);
this.iv = cipher.getIV();
} catch (Exception e) {
throw new CipherException("Error encrypting", e);
}
}
public OutputStream wrap(final OutputStream out) {
return new BufferedOutputStream(new OutputStream() {
#Override
public void write(int b) throws IOException {
}
#Override
public void write(byte[] plainBytes, int off, int len) throws IOException {
byte[] encryptedBytes = cipher.update(plainBytes, off, len);
if (encryptedBytes != null) {
out.write(encryptedBytes, 0, encryptedBytes.length);
}
}
#Override
public void flush() throws IOException {
out.flush();
}
#Override
public void close() throws IOException {
try {
byte[] encryptedBytes = cipher.doFinal();
if (encryptedBytes != null) {
out.write(encryptedBytes, 0, encryptedBytes.length);
}
} catch (Exception e) {
throw new IOException("Error encrypting", e);
}
out.close();
}
});
}
public SecretKey getSKey() {
return sKey;
}
public byte[] getIv() {
return iv;
}
}
public static class DecryptedInputStreamWrapper {
private Cipher cipher;
public DecryptedInputStreamWrapper(SecretKey sKey, byte[] iv) {
try {
this.cipher = Cipher.getInstance(AES_TRANSFORMATION);
this.cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(iv));
} catch (Exception e) {
throw new CipherException("Error decrypting", e);
}
}
public InputStream wrap(final InputStream in) {
return new BufferedInputStream(new InputStream() {
private byte[] buffer = new byte[DEFAULT_BUFFERSIZE];
private boolean done;
#Override
public int read() throws IOException {
return 0;
}
#Override
public int read(byte[] bytes, int off, int len) throws IOException {
if (done) {
return -1;
}
int encryptedLen = in.read(buffer);
try {
byte[] plainBytes = null;
if (encryptedLen == -1) {
done = true;
plainBytes = cipher.doFinal();
} else {
plainBytes = cipher.update(buffer, 0, encryptedLen);
}
if (plainBytes != null) {
System.arraycopy(plainBytes, 0, bytes, off, plainBytes.length);
return plainBytes.length;
}
} catch (Exception e) {
throw new IOException("Error decrypting", e);
}
return 0;
}
#Override
public void close() throws IOException {
in.close();
}
});
}
}
public static class CipherException extends RuntimeException {
private static final long serialVersionUID = 1L;
public CipherException() {
super();
}
public CipherException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public CipherException(String message, Throwable cause) {
super(message, cause);
}
public CipherException(String message) {
super(message);
}
public CipherException(Throwable cause) {
super(cause);
}
}
public static String randomText() {
StringBuilder sb = new StringBuilder();
int textLength = rnd(100000, 999999);
for (int i = 0; i < textLength; i++) {
if (rnd(0, 1) == 0) {
sb.append((char) rnd(65, 90));
} else {
sb.append((char) rnd(49, 57));
}
}
return sb.toString();
}
public static int rnd(int min, int max) {
return min + (int) (Math.random() * ((max - min) + 1));
}

Get metadata from shoutcast stream

I'm developing a radio app with multiple radios, the stream is playing fine. But I'm struggling to show artist and music playing at the moment.
This is the class I'm using to get metadata from shoutcast stream:
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IcyStreamMeta<Message> {
protected URL streamUrl;
private Map<String, String> metadata;
private boolean isError;
public IcyStreamMeta(URL streamUrl) {
setStreamUrl(streamUrl);
isError = false;
}
/**
* Get artist using stream's title
*
* #return String
* #throws IOException
*/
public String getArtist() throws IOException {
Map<String, String> data = getMetadata();
if (!data.containsKey("StreamTitle"))
return "";
String streamTitle = data.get("StreamTitle");
String title = streamTitle.substring(0, streamTitle.indexOf("-"));
return title.trim();
}
/**
* Get title using stream's title
*
* #return String
* #throws IOException
*/
public String getTitle() throws IOException {
Map<String, String> data = getMetadata();
if (!data.containsKey("StreamTitle"))
return "";
String streamTitle = data.get("StreamTitle");
String artist = streamTitle.substring(streamTitle.indexOf("-")+1);
return artist.trim();
}
public Map<String, String> getMetadata() throws IOException {
if (metadata == null) {
refreshMeta();
}
return metadata;
}
public void refreshMeta() throws IOException {
retreiveMetadata();
}
private void retreiveMetadata() throws IOException {
URLConnection con = streamUrl.openConnection();
con.setRequestProperty("Icy-MetaData", "1");
con.setRequestProperty("Connection", "close");
con.setRequestProperty("Accept", null);
con.connect();
int metaDataOffset = 0;
Map<String, List<String>> headers = con.getHeaderFields();
InputStream stream = con.getInputStream();
if (headers.containsKey("icy-metaint")) {
// Headers are sent via HTTP
metaDataOffset = Integer.parseInt(headers.get("icy-metaint").get(0));
} else {
// Headers are sent within a stream
StringBuilder strHeaders = new StringBuilder();
char c;
while ((c = (char)stream.read()) != -1) {
strHeaders.append(c);
if (strHeaders.length() > 5 && (strHeaders.substring((strHeaders.length() - 4), strHeaders.length()).equals("\r\n\r\n"))) {
// end of headers
break;
}
}
// Match headers to get metadata offset within a stream
Pattern p = Pattern.compile("\\r\\n(icy-metaint):\\s*(.*)\\r\\n");
Matcher m = p.matcher(strHeaders.toString());
if (m.find()) {
metaDataOffset = Integer.parseInt(m.group(2));
}
}
// In case no data was sent
if (metaDataOffset == 0) {
isError = true;
return;
}
// Read metadata
int b;
int count = 0;
int metaDataLength = 4080; // 4080 is the max length
boolean inData = false;
StringBuilder metaData = new StringBuilder();
// Stream position should be either at the beginning or right after headers
while ((b = stream.read()) != -1) {
count++;
// Length of the metadata
if (count == metaDataOffset + 1) {
metaDataLength = b * 16;
}
if (count > metaDataOffset + 1 && count < (metaDataOffset + metaDataLength)) {
inData = true;
} else {
inData = false;
}
if (inData) {
if (b != 0) {
metaData.append((char)b);
}
}
if (count > (metaDataOffset + metaDataLength)) {
break;
}
}
// Set the data
metadata = IcyStreamMeta.parseMetadata(metaData.toString());
// Close
stream.close();
}
public boolean isError() {
return isError;
}
public URL getStreamUrl() {
return streamUrl;
}
public void setStreamUrl(URL streamUrl) {
this.metadata = null;
this.streamUrl = streamUrl;
this.isError = false;
}
public static Map<String, String> parseMetadata(String metaString) {
Map<String, String> metadata = new HashMap();
String[] metaParts = metaString.split(";");
Pattern p = Pattern.compile("^([a-zA-Z]+)=\\'([^\\']*)\\'$");
Matcher m;
for (int i = 0; i < metaParts.length; i++) {
m = p.matcher(metaParts[i]);
if (m.find()) {
metadata.put(m.group(1), m.group(2));
}
}
return metadata;
}
}
And the method on MainActivity to get the metadata every 10 seconds
private void getMeta()
{
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
try {
IcyStreamMeta icy = new IcyStreamMeta(new URL(RadiophonyService.getRadioURL()));
final String data = icy.getArtist() + " - " + icy.getTitle();
final TextView meta = (TextView) findViewById(R.id.now_playing);
runOnUiThread(new Runnable() {
public void run() {
meta.setText(data);
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}, 0, 10000);
}
Initially, when I select one station, it plays but does not show metadata and when I select another station the app crashes with this runtime error:
E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.example.app, PID: 23597
java.lang.StringIndexOutOfBoundsException: length=0; regionStart=0; regionLength=-1
at java.lang.String.startEndAndLength(String.java:504)
at java.lang.String.substring(String.java:1333)
at com.example.app.utilities.IcyStreamMeta.getArtist(IcyStreamMeta.java:41)
at com.example.app.activities.MainActivity$8.run(MainActivity.java:306)
at java.util.Timer$TimerImpl.run(Timer.java:284)
I'm stuck at this for days, and I tried other solutions but nothing works!
Looks like this line
String title = streamTitle.substring(0, streamTitle.indexOf("-"));
is the culprit.
If streamTitle does not have a dash in its title, indexOf() will return a -1, and substring() is choking because you can't have an end index less than the start index.
Maybe you need something like this:
int pos = streamTitle.indexOf("-");
String title = (pos == -1) ? streamTitle : streamTitle.substring(0, pos);

How to convert JPG image to DICOM file using dcm4che-3.2.1?

I can set the attributes and create the dicom file, but I can not write the image to the dicom file?
I've tried it with an image I have and it works but I expect it won't work for RGB images. Something like this though
BufferedImage jpg = ImageIO.read(new File("myjpg.jpg"));
//Convert the image to a byte array
DataBufferUShort buff = (DataBufferUShort) jpg.getData().getDataBuffer();
short[] data = buff.getData();
ByteBuffer byteBuf = ByteBuffer.allocate(2*data.length);
int i = 0;
while (data.length > i) {
byteBuf.putShort(data[i]);
i++;
}
//Copy a header
DicomInputStream dis = new DicomInputStream(new File("fileToCopyheaderFrom.dcm"));
Attributes meta = dis.readFileMetaInformation();
Attributes attribs = dis.readDataset(-1, Tag.PixelData);
dis.close();
//Change the rows and columns
attribs.setInt(Tag.Rows, VR.US, jpg.getHeight());
attribs.setInt(Tag.Columns, VR.US, jpg.getWidth());
System.out.println(byteBuf.array().length);
//Attributes attribs = new Attributes();
//Write the file
attribs.setBytes(Tag.PixelData, VR.OW, byteBuf.array());
DicomOutputStream dcmo = new DicomOutputStream(new File("myDicom.dcm"));
dcmo.writeFileMetaInformation(meta);
attribs.writeTo(dcmo);
dcmo.close();
Edit 1
I've assumed your image has an Unsigned short Data Buffer here.
DataBufferUShort buff = (DataBufferUShort) jpg.getData().getDataBuffer();
To handle other data buffers you should check the type , cast acordingly and then convert to a byte array. For a byte Buffer it should be easy
DataBufferByte buff = (DataBufferByte) jpg.getData().getDataBuffer();
Then
buff.getData(numOfBank)
where numOfBank is 0 for you image
should return a byte array
This Code is Convert JPG file to Dicom File
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.dcm4che2.data.DicomObject;
import org.dcm4che2.data.Tag;
import org.dcm4che2.data.VR;
import org.dcm4che2.io.DicomInputStream;
import org.dcm4che2.io.DicomOutputStream;
public class JPG_TO_DCM {
public static void main(String a[]) throws FileNotFoundException, IOException
{
// System.out.println("JPG2DCM_Convert.main()");
String patientID="123"; // Enter Patient ID
String patientName="DCM IMAGE"; // Enter Pantient Name
String studyID="123"; // Enter Study ID
Jpg2Dcm jpg2Dcm = new Jpg2Dcm(); //
File jpgFileOS = new File("D:\\AA.jpg");
File dcmFileOS = new File("D:\\AA.dcm");
try {
jpg2Dcm.convert(jpgFileOS, dcmFileOS); // Only Convert Jpg to Dicom without seting any dicom tag (without DicomHeader)
} catch (IOException e) {
e.printStackTrace();
}
try {
anonymizeDicom(new File("D:\\AA.dcm"),new File("D:\\AA_FIANAL.dcm"),patientID,studyID,patientName); // Set the DICOM Header
} catch (Exception e) {
e.printStackTrace();
}
}
public static final int[] TAGS = {
Tag.PatientID,
Tag.StudyID,
Tag.PatientName
};
public static void anonymizeDicom(File fileInput, File fileOutput, String patientIDForUpdate, String studyIDForUpdate,String patientNameForUpdate) throws FileNotFoundException, IOException
{
int patientID = 1048608;
int studyID = 2097168;
int patientName=1048592;
try
{
FileInputStream fis = new FileInputStream(fileInput);
DicomInputStream dis = new DicomInputStream(fis);
DicomObject obj = dis.readDicomObject();
for (int tag : TAGS)
{
if (tag == patientID) {
replaceTag(obj, tag, patientIDForUpdate);
}
if (tag == studyID) {
replaceTag(obj, tag, studyIDForUpdate);
}
if (tag == patientName) {
replaceTag(obj, tag, patientNameForUpdate);
}
}
fis.close();
dis.close();
writeDicomFile(obj, fileOutput);
} catch (Exception e) {
e.printStackTrace();
}
}
#SuppressWarnings("unused")
private static String[] getValue(DicomObject object, int[] PATIENT_ADDITIONAL_TAGS)
{
String [] value = new String [PATIENT_ADDITIONAL_TAGS.length];
int i =0;
while (i<PATIENT_ADDITIONAL_TAGS.length)
{
for (int tag : PATIENT_ADDITIONAL_TAGS)
{
value[i]=object.getString(tag);
i++;
}
}
return value;
}
public static void replaceTag(DicomObject dObj, int tag, String newValue) {
if (tag != 0 && dObj.contains(tag)) {
VR vr = dObj.vrOf(tag);
try
{
dObj.putString(tag, vr, newValue);
} catch (Exception e) {
// System.err.println("Error replacing Tag: " + tag+ " with new value: " + newValue);
}
}
}
public static void writeDicomFile(DicomObject dObj, File f) {
FileOutputStream fos;
try
{
fos = new FileOutputStream(f);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
return;
}
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
try {
dos.writeDicomFile(dObj);
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
try {
dos.close();
} catch (IOException ignore) {
}
}
}
static int count1 = 0;
public static void getFile(String dirPath, String destdirPath,String patientID, String studyID,String patientNameForUpdate) throws FileNotFoundException,IOException
{
File f = new File(dirPath);
File[] files = f.listFiles();
if (files != null)
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isDirectory()) {
getFile(file.getAbsolutePath(), destdirPath, patientID,studyID,patientNameForUpdate);
} else {
count1++;
String name = file.getAbsolutePath();
// test7 test = new test7();
anonymizeDicom(new File(name), new File(destdirPath+ "/" + file.getName()), patientID, studyID,patientNameForUpdate);
}
}
}
}
Jpg2Dcm.java File
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.dcm4che2.data.BasicDicomObject;
import org.dcm4che2.data.DicomObject;
import org.dcm4che2.data.Tag;
import org.dcm4che2.data.UID;
import org.dcm4che2.data.VR;
import org.dcm4che2.io.DicomOutputStream;
import org.dcm4che2.util.UIDUtils;
public class Jpg2Dcm {
private static final String USAGE =
"jpg2dcm [Options] <jpgfile> <dcmfile>";
private static final String DESCRIPTION =
"Encapsulate JPEG Image into DICOM Object.\nOptions:";
private static final String EXAMPLE =
"--\nExample 1: Encapulate JPEG Image verbatim with default values " +
"for mandatory DICOM attributes into DICOM Secondary Capture Image:" +
"\n$ jpg2dcm image.jpg image.dcm" +
"\n--\nExample 2: Encapulate JPEG Image without application segments " +
"and additional DICOM attributes to mandatory defaults into DICOM " +
"Image Object:" +
"\n$ jpg2dcm --no-appn -c patattrs.cfg homer.jpg image.dcm" +
"\n--\nExample 3: Encapulate MPEG2 Video with specified DICOM " +
"attributes into DICOM Video Object:" +
"\n$ jpg2dcm --mpeg -C mpg2dcm.cfg video.mpg video.dcm";
private static final String LONG_OPT_CHARSET = "charset";
private static final String OPT_CHARSET_DESC =
"Specific Character Set code string, ISO_IR 100 by default";
private static final String OPT_AUGMENT_CONFIG_DESC =
"Specifies DICOM attributes included additional to mandatory defaults";
private static final String OPT_REPLACE_CONFIG_DESC =
"Specifies DICOM attributes included instead of mandatory defaults";
private static final String LONG_OPT_TRANSFER_SYNTAX = "transfer-syntax";
private static final String OPT_TRANSFER_SYNTAX_DESC =
"Transfer Syntax; 1.2.840.10008.1.2.4.50 (JPEG Baseline) by default.";
private static final String LONG_OPT_MPEG = "mpeg";
private static final String OPT_MPEG_DESC =
"Same as --transfer-syntax 1.2.840.10008.1.2.4.100 (MPEG2).";
private static final String LONG_OPT_UID_PREFIX = "uid-prefix";
private static final String OPT_UID_PREFIX_DESC =
"Generate UIDs with given prefix, 1.2.40.0.13.1.<host-ip> by default.";
private static final String LONG_OPT_NO_APPN = "no-appn";
private static final String OPT_NO_APPN_DESC =
"Exclude application segments APPn from JPEG stream; " +
"encapsulate JPEG stream verbatim by default.";
private static final String OPT_HELP_DESC =
"Print this message";
private static final String OPT_VERSION_DESC =
"Print the version information and exit";
private static int FF = 0xff;
private static int SOF = 0xc0;
private static int DHT = 0xc4;
private static int DAC = 0xcc;
private static int SOI = 0xd8;
private static int SOS = 0xda;
private static int APP = 0xe0;
private String charset = "ISO_IR 100";
private String transferSyntax = UID.JPEGBaseline1;
private byte[] buffer = new byte[8192];
private int jpgHeaderLen;
private int jpgLen;
private boolean noAPPn = false;
private Properties cfg = new Properties();
public Jpg2Dcm() {
try {
cfg.load(Jpg2Dcm.class.getResourceAsStream("jpg2dcm.cfg"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public final void setCharset(String charset) {
this.charset = charset;
}
private final void setTransferSyntax(String uid) {
this.transferSyntax = uid;
}
private final void setNoAPPn(boolean noAPPn) {
this.noAPPn = noAPPn;
}
private void loadConfiguration(File cfgFile, boolean augment)
throws IOException {
Properties tmp = augment ? new Properties(cfg) : new Properties();
InputStream in = new BufferedInputStream(new FileInputStream(cfgFile));
try {
tmp.load(in);
} finally {
in.close();
}
cfg = tmp;
}
public void convert(File jpgFile, File dcmFile) throws IOException {
jpgHeaderLen = 0;
jpgLen = (int) jpgFile.length();
DataInputStream jpgInput = new DataInputStream(
new BufferedInputStream(new FileInputStream(jpgFile)));
try {
DicomObject attrs = new BasicDicomObject();
attrs.putString(Tag.SpecificCharacterSet, VR.CS, charset);
for (Enumeration en = cfg.propertyNames(); en.hasMoreElements();) {
String key = (String) en.nextElement();
int[] tagPath = Tag.toTagPath(key);
int last = tagPath.length-1;
VR vr = attrs.vrOf(tagPath[last]);
if (vr == VR.SQ) {
attrs.putSequence(tagPath);
} else {
attrs.putString(tagPath, vr, cfg.getProperty(key));
}
}
if (noAPPn || missingRowsColumnsSamplesPMI(attrs)) {
readHeader(attrs, jpgInput);
}
ensureUS(attrs, Tag.BitsAllocated, 8);
ensureUS(attrs, Tag.BitsStored, attrs.getInt(Tag.BitsAllocated));
ensureUS(attrs, Tag.HighBit, attrs.getInt(Tag.BitsStored) - 1);
ensureUS(attrs, Tag.PixelRepresentation, 0);
ensureUID(attrs, Tag.StudyInstanceUID);
ensureUID(attrs, Tag.SeriesInstanceUID);
ensureUID(attrs, Tag.SOPInstanceUID);
Date now = new Date();
attrs.putDate(Tag.InstanceCreationDate, VR.DA, now);
attrs.putDate(Tag.InstanceCreationTime, VR.TM, now);
attrs.initFileMetaInformation(transferSyntax);
FileOutputStream fos = new FileOutputStream(dcmFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
try {
dos.writeDicomFile(attrs);
dos.writeHeader(Tag.PixelData, VR.OB, -1);
dos.writeHeader(Tag.Item, null, 0);
dos.writeHeader(Tag.Item, null, (jpgLen+1)&~1);
dos.write(buffer, 0, jpgHeaderLen);
int r;
while ((r = jpgInput.read(buffer)) > 0) {
dos.write(buffer, 0, r);
}
if ((jpgLen&1) != 0) {
dos.write(0);
}
dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);
} finally {
dos.close();
}
} finally {
jpgInput.close();
}
}
private boolean missingRowsColumnsSamplesPMI(DicomObject attrs) {
return !(attrs.containsValue(Tag.Rows)
&& attrs.containsValue(Tag.Columns)
&& attrs.containsValue(Tag.SamplesPerPixel)
&& attrs.containsValue(Tag.PhotometricInterpretation)
);
}
private void readHeader(DicomObject attrs, DataInputStream jpgInput)
throws IOException {
if (jpgInput.read() != FF || jpgInput.read() != SOI
|| jpgInput.read() != FF) {
throw new IOException(
"JPEG stream does not start with FF D8 FF");
}
int marker = jpgInput.read();
int segmLen;
boolean seenSOF = false;
buffer[0] = (byte) FF;
buffer[1] = (byte) SOI;
buffer[2] = (byte) FF;
buffer[3] = (byte) marker;
jpgHeaderLen = 4;
while (marker != SOS) {
segmLen = jpgInput.readUnsignedShort();
if (buffer.length < jpgHeaderLen + segmLen + 2) {
growBuffer(jpgHeaderLen + segmLen + 2);
}
buffer[jpgHeaderLen++] = (byte) (segmLen >>> 8);
buffer[jpgHeaderLen++] = (byte) segmLen;
jpgInput.readFully(buffer, jpgHeaderLen, segmLen - 2);
if ((marker & 0xf0) == SOF && marker != DHT && marker != DAC) {
seenSOF = true;
int p = buffer[jpgHeaderLen] & 0xff;
int y = ((buffer[jpgHeaderLen+1] & 0xff) << 8)
| (buffer[jpgHeaderLen+2] & 0xff);
int x = ((buffer[jpgHeaderLen+3] & 0xff) << 8)
| (buffer[jpgHeaderLen+4] & 0xff);
int nf = buffer[jpgHeaderLen+5] & 0xff;
attrs.putInt(Tag.SamplesPerPixel, VR.US, nf);
if (nf == 3) {
attrs.putString(Tag.PhotometricInterpretation, VR.CS,
"YBR_FULL_422");
attrs.putInt(Tag.PlanarConfiguration, VR.US, 0);
} else {
attrs.putString(Tag.PhotometricInterpretation, VR.CS,
"MONOCHROME2");
}
attrs.putInt(Tag.Rows, VR.US, y);
attrs.putInt(Tag.Columns, VR.US, x);
attrs.putInt(Tag.BitsAllocated, VR.US, p > 8 ? 16 : 8);
attrs.putInt(Tag.BitsStored, VR.US, p);
attrs.putInt(Tag.HighBit, VR.US, p-1);
attrs.putInt(Tag.PixelRepresentation, VR.US, 0);
}
if (noAPPn & (marker & 0xf0) == APP) {
jpgLen -= segmLen + 2;
jpgHeaderLen -= 4;
} else {
jpgHeaderLen += segmLen - 2;
}
if (jpgInput.read() != FF) {
throw new IOException("Missing SOS segment in JPEG stream");
}
marker = jpgInput.read();
buffer[jpgHeaderLen++] = (byte) FF;
buffer[jpgHeaderLen++] = (byte) marker;
}
if (!seenSOF) {
throw new IOException("Missing SOF segment in JPEG stream");
}
}
private void growBuffer(int minSize) {
int newSize = buffer.length << 1;
while (newSize < minSize) {
newSize <<= 1;
}
byte[] tmp = new byte[newSize];
System.arraycopy(buffer, 0, tmp, 0, jpgHeaderLen);
buffer = tmp;
}
private void ensureUID(DicomObject attrs, int tag) {
if (!attrs.containsValue(tag)) {
attrs.putString(tag, VR.UI, UIDUtils.createUID());
}
}
private void ensureUS(DicomObject attrs, int tag, int val) {
if (!attrs.containsValue(tag)) {
attrs.putInt(tag, VR.US, val);
}
}
public static void main(String[] args) {
try {
CommandLine cl = parse(args);
Jpg2Dcm jpg2Dcm = new Jpg2Dcm();
if (cl.hasOption(LONG_OPT_CHARSET)) {
jpg2Dcm.setCharset(cl.getOptionValue(LONG_OPT_CHARSET));
}
if (cl.hasOption("c")) {
jpg2Dcm.loadConfiguration(new File(cl.getOptionValue("c")), true);
}
if (cl.hasOption("C")) {
jpg2Dcm.loadConfiguration(new File(cl.getOptionValue("C")), false);
}
if (cl.hasOption(LONG_OPT_UID_PREFIX)) {
UIDUtils.setRoot(cl.getOptionValue(LONG_OPT_UID_PREFIX));
}
if (cl.hasOption(LONG_OPT_MPEG)) {
jpg2Dcm.setTransferSyntax(UID.MPEG2);
}
if (cl.hasOption(LONG_OPT_TRANSFER_SYNTAX)) {
jpg2Dcm.setTransferSyntax(
cl.getOptionValue(LONG_OPT_TRANSFER_SYNTAX));
}
jpg2Dcm.setNoAPPn(cl.hasOption(LONG_OPT_NO_APPN));
List argList = cl.getArgList();
File jpgFile = new File("d:\\VIPUL.jpg");
File dcmFile = new File("d:\\aa.dcm");
long start = System.currentTimeMillis();
jpg2Dcm.convert(jpgFile, dcmFile);
long fin = System.currentTimeMillis();
System.out.println("Encapsulated " + jpgFile + " to "
+ dcmFile + " in " + (fin - start) + "ms.");
} catch (IOException e) {
e.printStackTrace();
}
}
private static CommandLine parse(String[] args) {
Options opts = new Options();
OptionBuilder.withArgName("code");
OptionBuilder.hasArg();
OptionBuilder.withDescription(OPT_CHARSET_DESC);
OptionBuilder.withLongOpt(LONG_OPT_CHARSET);
opts.addOption(OptionBuilder.create());
OptionBuilder.withArgName("file");
OptionBuilder.hasArg();
OptionBuilder.withDescription(OPT_AUGMENT_CONFIG_DESC);
opts.addOption(OptionBuilder.create("c"));
OptionBuilder.withArgName("file");
OptionBuilder.hasArg();
OptionBuilder.withDescription(OPT_REPLACE_CONFIG_DESC);
opts.addOption(OptionBuilder.create("C"));
OptionBuilder.withArgName("prefix");
OptionBuilder.hasArg();
OptionBuilder.withDescription(OPT_UID_PREFIX_DESC);
OptionBuilder.withLongOpt(LONG_OPT_UID_PREFIX);
opts.addOption(OptionBuilder.create());
OptionBuilder.withArgName("uid");
OptionBuilder.hasArg();
OptionBuilder.withDescription(OPT_TRANSFER_SYNTAX_DESC);
OptionBuilder.withLongOpt(LONG_OPT_TRANSFER_SYNTAX);
opts.addOption(OptionBuilder.create());
opts.addOption(null, LONG_OPT_MPEG, false, OPT_MPEG_DESC);
opts.addOption(null, LONG_OPT_NO_APPN, false, OPT_NO_APPN_DESC);
opts.addOption("h", "help", false, OPT_HELP_DESC);
opts.addOption("V", "version", false, OPT_VERSION_DESC);
CommandLine cl = null;
try {
cl = new PosixParser().parse(opts, args);
} catch (ParseException e) {
exit("jpg2dcm: " + e.getMessage());
throw new RuntimeException("unreachable");
}
if (cl.hasOption('V')) {
Package p = Jpg2Dcm.class.getPackage();
System.out.println("jpg2dcm v" + p.getImplementationVersion());
System.exit(0);
}
if (cl.hasOption('h') || cl.getArgList().size() != 2) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(USAGE, DESCRIPTION, opts, EXAMPLE);
System.exit(0);
}
return cl;
}
private static void exit(String msg) {
System.err.println(msg);
System.err.println("Try 'jpg2dcm -h' for more information.");
System.exit(1);
}
}
Jpg2Dcm.java file use can also include below
org.dcm4che3.tool.dcm2jpg.Dcm2Jpg.java file
dcm4che-tool-dcm2jpg-3.3.7.jar
Also include this also
commons-cli-1.2.jar
dcm4che-core-2.0.26.jar
log4j-boot.jar
slf4j-api-1.5.0.jar
slf4j-log4j12-1.5.0.jar
Solver:
public jpgdcm(File file, File fileOutput) {
try {
jpgLen = (int) file.length();
BufferedImage jpegImage = ImageIO.read(file);
/*
* We open a try block and then read our Jpeg into a BufferedImage through ImageIO.read() method. If this results in an invalid image so we may throw a new exception.
* Else, we’ve got a valid image and therefore valuable information about it.
* The BufferedImage class has a lot of useful methods for retrieving image data, then let’s save the number of color components (samples per pixel) of our image, the bits
* per pixel and the bits allocated:
*/
if (jpegImage == null) throw new Exception("Invalid file.");
/* We open a try block and then read our Jpeg into a BufferedImage through ImageIO.read() method.
* If this results in an invalid image so we may throw a new exception.
* Else, we’ve got a valid image and therefore valuable information about it.
* The BufferedImage class has a lot of useful methods for retrieving image data,
* then let’s save the number of color components (samples per pixel) of our image,
* the bits per pixel and the bits allocated: */
int colorComponents = jpegImage.getColorModel().getNumColorComponents();
int bitsPerPixel = jpegImage.getColorModel().getPixelSize();
int bitsAllocated = (bitsPerPixel / colorComponents);
int samplesPerPixel = colorComponents;
/*It’s time to start building our Dicom dataset:*/
Attributes dicom = new Attributes();
dicom.setString(Tag.SpecificCharacterSet, VR.CS, "ISO_IR 100");
dicom.setString(Tag.PhotometricInterpretation, VR.CS, samplesPerPixel == 3 ? "YBR_FULL_422" : "MONOCHROME2");
/*The first line creates a new basic Dicom object defined by dcm4che2 toolkit.
*The next one puts header information for Specific Character Set: ISO_IR 100 – it’s the same for ISO-8859-1 – the code for Latin alphabet.
*Finally, the last line puts header information for photometric interpretation (read with or without colors).
*So if our image has samples per pixel equals to 3, it has colors (YBR_FULL_422), else it’s a grayscale image (MONOCHROME2).
The following lines add integer values to our Dicom header. Note that all of them comes from BufferedImage methods.
These values are mandatory when encapsulating. For more information you can check Part 3.5 of Dicom Standard. */
dicom.setInt(Tag.SamplesPerPixel, VR.US, samplesPerPixel);
dicom.setInt(Tag.Rows, VR.US, jpegImage.getHeight());
dicom.setInt(Tag.Columns, VR.US, jpegImage.getWidth());
dicom.setInt(Tag.BitsAllocated, VR.US, bitsAllocated);
dicom.setInt(Tag.BitsStored, VR.US, bitsAllocated);
dicom.setInt(Tag.HighBit, VR.US, bitsAllocated-1);
dicom.setInt(Tag.PixelRepresentation, VR.US, 0);
/*Also, our Dicom header needs information about date and time of creation:*/
dicom.setDate(Tag.InstanceCreationDate, VR.DA, new Date());
dicom.setDate(Tag.InstanceCreationTime, VR.TM, new Date());
/* Every Dicom file has a unique identifier.
* Here we’re generating study, series and Sop instances UIDs.
* You may want to modify these values, but you should to care about their uniqueness.
*/
dicom.setString(Tag.StudyInstanceUID, VR.UI, UIDUtils.createUID());
dicom.setString(Tag.SeriesInstanceUID, VR.UI, UIDUtils.createUID());
dicom.setString(Tag.SOPInstanceUID, VR.UI, UIDUtils.createUID());
dicom.setString(Tag.StudyInstanceUID, VR.UI, UIDUtils.createUID());
dicom.setString(Tag.SeriesInstanceUID, VR.UI, UIDUtils.createUID());
dicom.setString(Tag.SOPInstanceUID, VR.UI, UIDUtils.createUID());
/*Our Dicom header is almost done.
* The following command initiates Dicom metafile information considering JPEGBaseline1 as transfer syntax.
* This means this file has Jpeg data encapsulated instead common medical image pixel data.
* The most common Jpeg files use a subset of the Jpeg standard called baseline Jpeg.
* A baseline Jpeg file contains a single image compressed with the baseline discrete cosine transformation (DCT) and Huffman encoding.
*/
// dicom.initFileMetaInformation(UID.JPEGBaseline1);
/*After initiate the header we can open an output stream for saving our Dicom dataset as follows:*/
Attributes fmi = new Attributes();
fmi.setString(Tag.ImplementationVersionName, VR.SH, "DCM4CHE3");
fmi.setString(Tag.ImplementationClassUID, VR.UI, UIDUtils.createUID());
fmi.setString(Tag.TransferSyntaxUID, VR.UI, transferSyntax);
fmi.setString(Tag.MediaStorageSOPClassUID, VR.UI, transferSyntax);
fmi.setString(Tag.MediaStorageSOPInstanceUID, VR.UI,UIDUtils.createUID());
fmi.setString(Tag.FileMetaInformationVersion, VR.OB, "1");
fmi.setInt(Tag.FileMetaInformationGroupLength, VR.UL, dicom.size()+fmi.size());
DicomOutputStream dos = new DicomOutputStream(fileOutput);
dos.writeDataset(fmi, dicom);
dos.writeHeader(Tag.PixelData, VR.OB, -1);
/*
* The Item Tag (FFFE,E000) is followed by a 4 byte item length field encoding the explicit number of bytes of the item.
* The first item in the sequence of items before the encoded pixel data stream shall be a basic item with length equals to zero:
*/
dos.writeHeader(Tag.Item, null, 0);
/*The next Item then keeps the length of our Jpeg file. */
/*
According to Gunter from dcm4che team we have to take care that
the pixel data fragment length containing the JPEG stream has
an even length.
*/
dos.writeHeader(Tag.Item, null, (jpgLen+1)&~1);
/* Now all we have to do is to fill this item with bytes taken from our Jpeg file*/
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
byte[] buffer = new byte[65536];
int b;
while ((b = dis.read(buffer)) > 0) {
dos.write(buffer, 0, b);
}
/*Finally, the Dicom Standard tells that we have to put a last Tag:
* a Sequence Delimiter Item (FFFE,E0DD) with length equals to zero.*/
if ((jpgLen&1) != 0) dos.write(0);
dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);
dos.close();
} catch (Exception e) {
e.printStackTrace();
}
}

Categories

Resources