Java 如何把图片JPG转成Dicom文件

网上查了许多资料,比较少有能用Java把普通的图片转成dicom文件(.dcm)的方法。
这里提供一个自己整合的 直接可用的转换方法,主要用了dcm4che。这是一个现在还在持续更新,功能还算较全面的Java版Dicom处理工具了,里面有很多小工具可以根据自己的项目改编使用。其中就有一个工具是jpg2dcm,满足从jpg图片转成.dcm文件,然后我根据自己的需求改写了方法,使其整合到一个通用的springboot项目中。这个方法其实还可以转视频文件到dicom文件,只不过我这里只满足图片转dicom的需求所以暂时删除了,但可以根据需要很方便的添加上:)

Dependencies

  • JDK 1.8

  • dcm4che-core:5.22.4

  • dcm4che-imageio:5.22.4

  • dcm4che-tool-common:5.22.4

  • commons-cli:1.4

Code

工具类

/*
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 *  The contents of this file are subject to the Mozilla Public License Version
 *  1.1 (the "License"); you may not use this file except in compliance with
 *  the License. You may obtain a copy of the License at
 *  http://www.mozilla.org/MPL/
 *
 *  Software distributed under the License is distributed on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 *  for the specific language governing rights and limitations under the
 *  License.
 *
 *  The Original Code is part of dcm4che, an implementation of DICOM(TM) in
 *  Java(TM), hosted at https://github.com/dcm4che.
 *
 *  The Initial Developer of the Original Code is
 *  J4Care.
 *  Portions created by the Initial Developer are Copyright (C) 2015-2019
 *  the Initial Developer. All Rights Reserved.
 *
 *  Contributor(s):
 *  See @authors listed below
 *
 *  Alternatively, the contents of this file may be used under the terms of
 *  either the GNU General Public License Version 2 or later (the "GPL"), or
 *  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 *  in which case the provisions of the GPL or the LGPL are applicable instead
 *  of those above. If you wish to allow use of your version of this file only
 *  under the terms of either the GPL or the LGPL, and not to allow others to
 *  use your version of this file under the terms of the MPL, indicate your
 *  decision by deleting the provisions above and replace them with the notice
 *  and other provisions required by the GPL or the LGPL. If you do not delete
 *  the provisions above, a recipient may use your version of this file under
 *  the terms of any one of the MPL, the GPL or the LGPL.
 *
 */

/**
 * Original package:
 * https://github.com/dcm4che/dcm4che/blob/master/dcm4che-tool/dcm4che-tool-jpg2dcm/src/main/java/org/dcm4che3/tool/jpg2dcm/Jpg2Dcm.java
 */

package org.demo.com.util;

import org.dcm4che3.data.*;
import org.dcm4che3.imageio.codec.XPEGParser;
import org.dcm4che3.imageio.codec.jpeg.JPEGParser;
import org.dcm4che3.io.DicomOutputStream;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.*;

public class Jpg2DcmUtil {
    private static final int BUFFER_SIZE = 8162;
    private static byte[] buf = new byte[BUFFER_SIZE];

    public static void convert(Path srcFilePath, Path destFilePath, Attributes metaData) throws Exception {
        Attributes fileMetadata = new Attributes();
        fileMetadata.addAll(metaData);
        try (SeekableByteChannel channel = Files.newByteChannel(srcFilePath);
             DicomOutputStream dos = new DicomOutputStream(destFilePath.toFile())) {
            XPEGParser parser = new JPEGParser(channel);
            parser.getAttributes(fileMetadata);
            dos.writeDataset(fileMetadata.createFileMetaInformation(parser.getTransferSyntaxUID()), fileMetadata);
            dos.writeHeader(Tag.PixelData, VR.OB, -1);
            dos.writeHeader(Tag.Item, null, 0);
            copyPixelData(channel, parser.getCodeStreamPosition(), dos);
            dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);
            System.out.println("converted");
        }
    }

    private static void copyPixelData(SeekableByteChannel channel, long position, DicomOutputStream dos, byte... prefix)
            throws IOException {
        long codeStreamSize = channel.size() - position + prefix.length;
        dos.writeHeader(Tag.Item, null, (int) ((codeStreamSize + 1) & ~1));
        dos.write(prefix);
        channel.position(position);
        copy(channel, dos);
        if ((codeStreamSize & 1) != 0)
            dos.write(0);
    }

    private static void copy(ByteChannel in, OutputStream out) throws IOException {
        ByteBuffer bb = ByteBuffer.wrap(buf);
        int read;
        while ((read = in.read(bb)) > 0) {
            out.write(buf, 0, read);
            bb.clear();
        }
    }
}

应用

package org.demo.com.service;

import org.demo.com.util.Jpg2DcmUtil;
import org.dcm4che3.data.*;
import org.dcm4che3.util.UIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;

@Service
public class DicomService {
  
    private static final ElementDictionary DICT = ElementDictionary.getStandardElementDictionary();
    private static final int[] TYPE2_TAGS = {
            Tag.ContentDate,
            Tag.ContentTime
    };
  
    public void convertJpg2Dcm(String srcPath, String destPath) throws Exception {
      
        // 根据需求加入dicom里的tag信息
        Attributes staticMetadata = new Attributes();

        // set ID
        staticMetadata.setString(Tag.StudyInstanceUID, VR.UI, UIDUtils.createUID()); 
        staticMetadata.setString(Tag.SeriesInstanceUID, VR.UI, UIDUtils.createUID());
        staticMetadata.setString(Tag.SOPInstanceUID, VR.UI, UIDUtils.createUID());

        // patient info
        setMetadata(staticMetadata, Tag.PatientName, "Test Patient");
        setMetadata(staticMetadata, Tag.PatientID, "Test Patient");
        setMetadata(staticMetadata, Tag.PatientSex, "M");
        setMetadata(staticMetadata, Tag.PatientAge, "50");
        setMetadata(staticMetadata, Tag.PatientBirthDate, "19500101");

        // study info
        setMetadata(staticMetadata, Tag.StudyDate, "20100101");
        setMetadata(staticMetadata, Tag.StudyTime, "123");
        setMetadata(staticMetadata, Tag.StudyDescription, "Study Description");
        setMetadata(staticMetadata, Tag.StudyID, "123");

        // series info
        setMetadata(staticMetadata, Tag.SeriesDate, "20100101");
        setMetadata(staticMetadata, Tag.SeriesTime, "123");

        setMetadata(staticMetadata, Tag.SOPClassUID, UID.SecondaryCaptureImageStorage);
        supplementType2Tags(staticMetadata);

      
        // convert jpeg files to dicom files
        Path src = Paths.get(srcPath);
        Path dest = Paths.get(destPath);
        Jpg2DcmUtil.convert(src, dest, staticMetadata);
    }

    private void setMetadata(Attributes metadata, int tag, String value) {
//        if (!metadata.containsValue(tag))
        if (value != null)
            metadata.setString(tag, DICT.vrOf(tag), value);
    }

    private void supplementType2Tags(Attributes metadata) {
        for (int tag : TYPE2_TAGS)
            if (!metadata.contains(tag))
                metadata.setNull(tag, DICT.vrOf(tag));
    }
}

如果是其它图片格式(比如png),可以先转成jpeg或者jpg,就可以进行一步转化了。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值