/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package open.dolphin.utilities.common;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Formatter;
/**
* DICOMクラス
* @author S.Oh@Life Sciences Computing Corporation.
*/
public class Dicom extends AbstractCommonFunc {
protected boolean timeCheck = true;
protected long start;
protected long stop;
protected int setVM = 0;
protected boolean Implisit = true;
protected boolean meta = false;
protected int dep;
protected int mono;
protected int minus;
protected float RescaleS;
protected float RescaleI;
protected byte[] out8Data; //Raw
protected short[] out16Data; //Raw->SwapRaw
protected byte outdata[]; //RGB(24bit)
protected DataOutputStream dis;
protected ByteArrayOutputStream bmpData;
protected byte[] rawData;
protected int outDataSize;
protected int dataWidth;
protected int dataHeight;
protected float wcVal;
protected float wwVal;
protected float wcOffset;
protected float wwOffset;
/**
* コンストラクタ
*/
protected Dicom(){
super();
Init();
}
/**
* 初期化
*/
void Init() {
dep = 0;
mono = 0;
minus = 0;
RescaleI = 0;
RescaleS = 1;
out8Data = null;
out16Data = null;
outdata = null;
//UL = setString2VR("UL");
dis = null;
bmpData = null;
rawData = null;
outDataSize = 0;
dataWidth = 0;
dataHeight = 0;
wwVal = 0f;
wcVal = 0f;
wwOffset = 0f;
wcOffset = 0f;
}
/**
* DICOMファイルのオープン
* @param dcmFname ファイルパス
* @return 結果
*/
protected int dcm2bmpOpen(String dcmFname){
int ret =0;
ret = dcmGetraw(dcmFname);
if(mono != 2){
ret = dcmRaw2bmp();
ret = dcmRawFix();
}
return(ret);
}
/**
* 階調処理
* @param wc センター
* @param ww 幅
* @return 結果
*/
protected int changeWCWW(float wc, float ww){
int ret =0;
wwOffset += ww;
wcOffset += wc;
if(mono != 2){
//ret = dcmRaw2bmp();
ret = dcmRawFix();
}
return(ret);
}
/**
* 階調クリア
* @return 結果
*/
protected int clearWCWW(){
int ret =0;
wwOffset = 0;
wcOffset = 0;
if(mono != 2){
//ret = dcmRaw2bmp();
ret = dcmRawFix();
}
return(ret);
}
/**
* BMPファイルの保存
* @param bmpFname ファイルパス
* @param kind 種類
* @return 結果
*/
protected int dcm2bmpWrite(String bmpFname, int kind){
int ret =0;
if(mono == 2){
ret = dcmBmpRGBWrite(bmpFname, kind);
} else {
ret = dcmBmpGrayWrite(bmpFname, kind);
}
return(ret);
}
/**
* RGBの保存
* @param bmpFname ファイルパス
* @param kind 種類
* @return 結果
*/
protected int dcmBmpRGBWrite(String bmpFname, int kind){
if(timeCheck){
System.out.println("bmp Start");
start = System.currentTimeMillis();
}
int ret =0;
int i, j;
//int bit=1;
int real_width;
//byte header_buf[];
int file_size;
//int offset_to_data;
//long info_header_size;
short planes;
short color;
int compress;
int data_size;
int xppm;
int yppm;
byte data;
byte[] bmp;
int bmpsize;
real_width = dataWidth*3 + dataWidth%4;
file_size = dataHeight * real_width + HEADERSIZE;
bmp = new byte[file_size+1024];
planes = 1;
color = 24;
compress = 0;
data_size = dataHeight * real_width;
xppm = 1;
yppm = 1;
try{
//DataOutputStream dis = new DataOutputStream(new FileOutputStream(bmpFname));
if(kind == 0 && bmpFname != null) {
dis = new DataOutputStream(new FileOutputStream(bmpFname));
} else {
bmpData = new ByteArrayOutputStream();
dis = new DataOutputStream(bmpData);
}
dis.writeByte('B');
dis.writeByte('M');
file_size = data2LEUL(file_size);
dis.writeInt(file_size);
dis.writeInt(0);//Dummy
data = HEADERSIZE;
dis.writeByte(data);
dis.writeByte(0);
dis.writeByte(0);
dis.writeByte(0);
data = INFOHEADERSIZE;
dis.writeByte(data);
dis.writeByte(0);
dis.writeByte(0);
dis.writeByte(0);
int swidth = data2LEUL(dataWidth);
int sheight = data2LEUL(dataHeight);
short splanes = data2LEUS(planes);
short scolor = data2LEUS(color);
dis.writeInt(swidth);
dis.writeInt(sheight);
dis.writeShort(splanes);
dis.writeShort(scolor);
dis.writeInt(compress);
int sdata_size = data2LEUL(data_size);
dis.writeInt(sdata_size);
int sxppm = data2LEUL(xppm);
int syppm = data2LEUL(yppm);
dis.writeInt(sxppm);
dis.writeInt(syppm);
dis.writeInt(0);//Dummy
dis.writeInt(0);//Dummy
//for(i=0; i<height; i++){
if(false){
for(i=dataHeight-1; i>=0; i--){
bmp = new byte[real_width];
for(j=0; j<dataWidth; j++){
bmp[(j*3)] = out8Data[(i*dataWidth)+j];
bmp[(j*3)+1] = out8Data[(i*dataWidth)+j];
bmp[(j*3)+2] = out8Data[(i*dataWidth)+j];
}
//RGB情報を4バイトの倍数に合わせている
for(j=dataWidth*3; j<real_width; j++){
bmp[j] = 0;
}
dis.write(bmp,0,real_width);
bmpsize = real_width;
}
}else{
bmp = new byte[data_size];
int k,l=0;
for(i=dataHeight-1; i>=0; i--){
k = l*real_width;
for(j=0; j<dataWidth; j++){
//bmp[k+(j*3)] = out8Data[(i*dataWidth*3)+(j*3)+2];
//bmp[k+(j*3)+1] = out8Data[(i*dataWidth*3)+(j*3)+1];
//bmp[k+(j*3)+2] = out8Data[(i*dataWidth*3)+(j*3)];
byte b = out8Data[(i*dataWidth*3)+(j*3)+2];
byte g = out8Data[(i*dataWidth*3)+(j*3)+1];
byte r = out8Data[(i*dataWidth*3)+(j*3)];
short bTmp = (short) (b < 0 ? b + 256 : b);
short gTmp = (short) (g < 0 ? g + 256 : g);
short rTmp = (short) (r < 0 ? r + 256 : r);
bTmp = (short) (bTmp+wcOffset > 255 ? 255 : bTmp+wcOffset < 0 ? 0 : bTmp+wcOffset);
gTmp = (short) (gTmp+wcOffset > 255 ? 255 : gTmp+wcOffset < 0 ? 0 : gTmp+wcOffset);
rTmp = (short) (rTmp+wcOffset > 255 ? 255 : rTmp+wcOffset < 0 ? 0 : rTmp+wcOffset);
bmp[k+(j*3)] = (byte) bTmp;
bmp[k+(j*3)+1] = (byte) gTmp;
bmp[k+(j*3)+2] = (byte) rTmp;
}
//RGB情報を4バイトの倍数に合わせている
for(j=dataWidth*3; j<real_width; j++){
bmp[k+j] = 0;
}
l++;
}
dis.write(bmp,0,data_size);
bmpsize = data_size;
}
dis.close();
}
catch(Exception e){
System.out.println("書き込みに失敗");
ret = -1;
}
if(timeCheck){
stop = System.currentTimeMillis();
System.out.println("実行にかかった時間は " + (stop - start) + " ミリ秒です。");
System.out.println("bmp End");
}
return(ret);
}
/**
* グレースケールの保存
* @param bmpFname ファイルパス
* @param kind 種類
* @return 結果
*/
protected int dcmBmpGrayWrite(String bmpFname, int kind){
if(timeCheck){
System.out.println("bmp Start");
start = System.currentTimeMillis();
}
int ret =0;
int i, j;
//int bit=1;
int real_width;
//byte header_buf[];
int file_size;
//int offset_to_data;
//long info_header_size;
short planes;
short color;
int compress;
int data_size;
int xppm;
int yppm;
byte data;
byte[] bmp;
int bmpsize;
real_width = dataWidth*3 + dataWidth%4;
file_size = dataHeight * real_width + HEADERSIZE;
bmp = new byte[file_size+1024];
planes = 1;
color = 24;
compress = 0;
data_size = dataHeight * real_width;
xppm = 1;
yppm = 1;
try{
//DataOutputStream dis = new DataOutputStream(new FileOutputStream(bmpFname));
if(kind == 0 && bmpFname != null) {
dis = new DataOutputStream(new FileOutputStream(bmpFname));
} else {
bmpData = new ByteArrayOutputStream();
dis = new DataOutputStream(bmpData);
}
dis.writeByte('B');
dis.writeByte('M');
file_size = data2LEUL(file_size);
dis.writeInt(file_size);
dis.writeInt(0);//Dummy
data = HEADERSIZE;
dis.writeByte(data);
dis.writeByte(0);
dis.writeByte(0);
dis.writeByte(0);
data = INFOHEADERSIZE;
dis.writeByte(data);
dis.writeByte(0);
dis.writeByte(0);
dis.writeByte(0);
int swidth = data2LEUL(dataWidth);
int sheight = data2LEUL(dataHeight);
short splanes = data2LEUS(planes);
short scolor = data2LEUS(color);
dis.writeInt(swidth);
dis.writeInt(sheight);
dis.writeShort(splanes);
dis.writeShort(scolor);
dis.writeInt(compress);
int sdata_size = data2LEUL(data_size);
dis.writeInt(sdata_size);
int sxppm = data2LEUL(xppm);
int syppm = data2LEUL(yppm);
dis.writeInt(sxppm);
dis.writeInt(syppm);
dis.writeInt(0);//Dummy
dis.writeInt(0);//Dummy
//for(i=0; i<height; i++){
if(false){
for(i=dataHeight-1; i>=0; i--){
bmp = new byte[real_width];
for(j=0; j<dataWidth; j++){
bmp[(j*3)] = outdata[(i*dataWidth)+j];
bmp[(j*3)+1] = outdata[(i*dataWidth)+j];
bmp[(j*3)+2] = outdata[(i*dataWidth)+j];
}
//RGB情報を4バイトの倍数に合わせている
for(j=dataWidth*3; j<real_width; j++){
bmp[j] = 0;
}
dis.write(bmp,0,real_width);
bmpsize = real_width;
}
}else{
bmp = new byte[data_size];
int k,l=0;
for(i=dataHeight-1; i>=0; i--){
k = l*real_width;
for(j=0; j<dataWidth; j++){
bmp[k+(j*3)] = outdata[(i*dataWidth)+j];
bmp[k+(j*3)+1] = outdata[(i*dataWidth)+j];
bmp[k+(j*3)+2] = outdata[(i*dataWidth)+j];
}
//RGB情報を4バイトの倍数に合わせている
for(j=dataWidth*3; j<real_width; j++){
bmp[k+j] = 0;
}
l++;
}
dis.write(bmp,0,data_size);
bmpsize = data_size;
}
dis.close();
}
catch(Exception e){
System.out.println("書き込みに失敗");
ret = -1;
}
if(timeCheck){
stop = System.currentTimeMillis();
System.out.println("実行にかかった時間は " + (stop - start) + " ミリ秒です。");
System.out.println("bmp End");
}
return(ret);
}
/**
*
* @return 結果
*/
protected int dcmRawFix(){
if(timeCheck){
System.out.println("dcmRawFix Start");
start = System.currentTimeMillis();
}
int ret =0;
int i,j;
double dss;
int ddep =8;
//int wwdep;
// dcmGetraw()で処理
//int wwdep = 1<<dep;
//if(ww == 0.0 && wc == 0.0){
// wc = wwdep/2;
// ww = wwdep-1;
//}
double wdep = 1<<ddep;
wdep -= 1;
outdata = new byte[dataWidth*dataHeight+1024];
outDataSize = 0;
float wc = wcVal + wcOffset;
float ww = wwVal + wwOffset;
for(i=0; i<dataHeight; i++){
for(j=0; j<dataWidth; j++){
dss = out16Data[(i*dataWidth)+j];
dss = (dss*RescaleS)+RescaleI;
dss = dss -(wc-(ww/2));
dss = ((dss*(wdep))/ww);
if(dss > wdep){
dss = wdep;
}
if(dss < 0){
dss = 0;
}
if(mono == 1){
dss = wdep-dss;
}
outdata[(i*dataWidth)+j] = (byte)dss;
outDataSize += 1;
}
}
if(false){
try{
RandomAccessFile randomfile1 = new RandomAccessFile("d:\\img\\aaa.raw", "rw");
randomfile1.write(outdata);
randomfile1.close();
}
catch(IOException e){
System.out.println("Error");
ret = -1;
}
}
if(timeCheck){
stop = System.currentTimeMillis();
System.out.println("実行にかかった時間は " + (stop - start) + " ミリ秒です。");
System.out.println("dcmRawFix End");
}
return(ret);
}
/**
*
* @return 結果
*/
protected int dcmRaw2bmp(){
int k,i,j,ret =0;
short ss;
int wi,index;
if(timeCheck){
System.out.println("dcmRaw2bmp Start");
start = System.currentTimeMillis();
}
out16Data = new short[(int)out8Data.length];
wi=0;
byte ub;
for(i = 0;i<dataHeight;i++){
for(j = 0;j<dataWidth*2;j+=2){
index = (i*dataWidth*2)+j;
ub = (out8Data[index]);
ss = (short)(ub & 0xFF);
out16Data[wi] = ss;
ub = (out8Data[index+1]);
ss = (short)(ub & 0xFF);
out16Data[wi] += ss*=0x100;
//Formatter f = new Formatter();
//f.format("%04x",out16Data[wc]);
//String s = f.toString();
//System.out.println(s);;
wi++;
}
}
if(timeCheck){
stop = System.currentTimeMillis();
System.out.println(wi);
System.out.println(out16Data.length);
System.out.println("実行にかかった時間は " + (stop - start) + " ミリ秒です。");
System.out.println("dcmRaw2bmp End");
}
return(ret);
}
/**
*
* @param dcmFname ファイルパス
* @return 結果
*/
protected int dcmGetraw(String dcmFname){
//byte[] outData = null;
//BufferedReader br;
int ret = 0;
short g,e;
int len;
int index =0;
byte[] buf;
byte VR[];
short svr;
String s;
long seek =0;
int grpelm = 0x00000000;
try {
//Read
//File dcmFile = new File(dcmFname);
//outData = new char[(int) dcmFile.length()+1024];
RandomAccessFile dis = new RandomAccessFile(dcmFname,"r");
//DataInputStream dis = new DataInputStream(new FileInputStream(dcmFname));
//ByteBuffer bb = ByteBuffer.allocateDirect((int)dcmFile.length()+1024);
//bb.order(ByteOrder.LITTLE_ENDIAN);
dis.skipBytes(128);
buf = new byte[(int)4];
dis.read(buf);
VR = new byte[(int)2];
//seek = dis.getFilePointer();
s = new String( buf );
if(s.equals("DICM")){
meta = true;
while(true){
g = data2LEUS(dis.readShort());
e = data2LEUS(dis.readShort());
grpelm = geString2Hex(g,e);
if(grpelm >= 0x00080000){
seek = dis.getFilePointer();
break;
}
dis.read(VR);
svr =geString2VR(VR);
switch(svr){
case OB:
case OW:
case SQ:
case UN:
dis.readShort();//Dummy
len = data2LEUL(dis.readInt());
break;
default:
len = (int)data2LEUS(dis.readShort());
break;
}
buf = new byte[(int)len];
dis.read(buf);
switch(grpelm){
case 0x00020010:
//null Term
if(buf[len-1] == 0x00){
buf[len-1] = 0x20;
}
s = new String( buf );
s = s.replaceAll(" ", "");
if(s.equals("1.2.840.10008.1.2.1")){
Implisit = false;
}
break;
}
}
} else {
dis.seek(0);
}
if(meta == true){
dis.seek(seek-4);
}
while(grpelm != 0x7fe00010){
g = data2LEUS(dis.readShort());
e = data2LEUS(dis.readShort());
grpelm = geString2Hex(g,e);
Formatter f = new Formatter();
f.format("%08x",grpelm);
String gps = f.toString();
System.out.println(gps);
if(Implisit == false){
dis.read(VR);
svr =geString2VR(VR);
switch(svr){
case OB:
case OW:
case SQ:
case UN:
dis.readShort();//Dummy
len = data2LEUL(dis.readInt());
break;
default:
len = (int)data2LEUS(dis.readShort());
break;
}
} else {
len = data2LEUL(dis.readInt());
}
switch(grpelm){
case 0x00280004:
buf = new byte[(int)len];
dis.read(buf);
s = new String( buf );
//MONOCHEROME or RGB
if(s.equals("MONOCHROME1 ")){
mono = 1;
} else if(s.equals("MONOCHROME2 ")){
mono = 0;
} else if(s.equals("RGB ")){
mono = 2;
}
break;
case 0x00280010:
dataHeight = data2LEUS(dis.readShort());
break;
case 0x00280011:
dataWidth = data2LEUS(dis.readShort());
break;
case 0x00280101:
dep = data2LEUS(dis.readShort());
break;
case 0x00281050:
buf = new byte[(int)len];
dis.read(buf);
s = new String( buf );
wcVal = data2LEFL(s);
break;
case 0x00281051:
buf = new byte[(int)len];
dis.read(buf);
s = new String( buf );
wwVal = data2LEFL(s);
break;
case 0x00281052:
buf = new byte[(int)len];
dis.read(buf);
s = new String( buf );
RescaleI = data2LEFL(s);
break;
case 0x00281053:
buf = new byte[(int)len];
dis.read(buf);
s = new String( buf );
RescaleS = data2LEFL(s);
break;
case 0x7fe00010:
if(timeCheck){
start = System.currentTimeMillis();
}
out8Data = new byte[(int)len];
dis.read(out8Data);
outDataSize = len;
if(timeCheck){
stop = System.currentTimeMillis();
System.out.println("画像読込みにかかった時間は " + (stop - start) + " ミリ秒です。");
}
break;
default:
if(len == 0xFFFFFFFF){
ret = readFFFFLength(dis);
} else {
buf = new byte[(int)len];
dis.read(buf);
}
break;
}
}
int wwdep = 1<<dep;
if(wwVal == 0.0 && wcVal == 0.0){
wwVal = wwdep-1;
wcVal = wwdep/2;
}
}
catch(Exception ex){
System.out.println("ファイル例外"+ex+"が発生しました");
ret = -1;
}
return(ret);
}
/**
*
* @param dis
* @return 結果
*/
protected int readFFFFLength(RandomAccessFile dis){
int ret=0;
short g,e;
int grpelm;
int len;
byte [] buf;
boolean loop = true;
try{
//System.out.println("readFFFFLengthS "+dis.length()+" が発生しました");
while(loop){
g = data2LEUS(dis.readShort());
e = data2LEUS(dis.readShort());
grpelm = geString2Hex(g,e);
switch(grpelm){
case 0xFFFEE000:
len = data2LEUL(dis.readInt());
if(len == 0xFFFFFFFF){
ret = readFFFFLength(dis);
} else {
buf = new byte[(int)len];
dis.read(buf);
}
break;
case 0xFFFEE00D:
len = data2LEUL(dis.readInt());
loop = false;
break;
case 0xFFFEE0DD:
len = data2LEUL(dis.readInt());
loop = false;
break;
default:
len = data2LEUL(dis.readInt());
buf = new byte[(int)len];
dis.read(buf);
break;
}
}
//System.out.println("readFFFFLengthE"+dis.length()+"が発生しました");
}
catch(Exception ex){
System.out.println("ファイル例外"+ex+"が発生しました");
ret = -1;
}
return(ret);
}
/**
*
* @param g グループ
* @param e エレメント
* @return 結果
*/
protected int geString2Hex(int g,int e){
int GrpElm=0;
GrpElm = (g<<16) & 0xFFFF0000;
GrpElm += e & 0x0000FFFF;
return(GrpElm);
}
/**
*
* @param VR VR
* @return VR
*/
protected short setString2VR(String VR){
short vr=0;
int ch;
ch= Character.codePointAt(VR, 0);
vr = (short)(ch*0x100);
ch= Character.codePointAt(VR, 1);
vr += (short)ch;
return(vr);
}
/**
*
* @param VR VR
* @return VR
*/
protected short geString2VR(byte VR[]){
short vr=0;
vr = VR[1];
vr += VR[0]*0x100;
return(vr);
}
/**
*
* @param us US
* @return US
*/
protected short data2LEUS(short us){
short retUS;
ByteBuffer bb = ByteBuffer.allocateDirect(2);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putShort(us);
bb.order(ByteOrder.LITTLE_ENDIAN);
retUS = bb.getShort(0);
return(retUS);
}
/**
*
* @param ul UL
* @return UL
*/
protected int data2LEUL(int ul){
int retUL;
ByteBuffer bb = ByteBuffer.allocateDirect(4);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putInt(ul);
bb.order(ByteOrder.LITTLE_ENDIAN);
retUL = bb.getInt(0);
return(retUL);
}
/**
*
* @param ds DS
* @return DS
*/
protected int data2LEDS(String ds){
int ids=0;
ds = ds.replaceAll(" ", "");
ids = Integer.parseInt(ds);
return(ids);
}
/**
*
* @param fl FL
* @return FL
*/
protected float data2LEFL(String fl){
float ifl=0;
int p;
p = fl.indexOf('\\');
if(p == -1){
fl = fl.replaceAll(" ", "");
} else {
fl = fl.substring(0,p);
}
ifl = Float.parseFloat(fl);
return(ifl);
}
}