コード例 #1
0
    Instance(ServerIndex& index,
             const std::string& instanceId) :
      instanceId_(instanceId),
      framesCount_(1)
    {
      DicomMap instance;
      if (!index.GetMainDicomTags(instance, instanceId, ResourceType_Instance, ResourceType_Instance))
      {
        throw OrthancException(ErrorCode_UnknownResource);
      }

      const DicomValue* frames = instance.TestAndGetValue(DICOM_TAG_NUMBER_OF_FRAMES);
      if (frames != NULL &&
          !frames->IsNull() &&
          !frames->IsBinary())
      {
        try
        {
          framesCount_ = boost::lexical_cast<unsigned int>(frames->GetContent());
        }
        catch (boost::bad_lexical_cast&)
        {
        }
      }
      
      std::vector<float> tmp;
      hasPosition_ = TokenizeVector(tmp, instance, DICOM_TAG_IMAGE_POSITION_PATIENT, 3);

      if (hasPosition_)
      {
        position_[0] = tmp[0];
        position_[1] = tmp[1];
        position_[2] = tmp[2];
      }

      std::string s;
      hasIndexInSeries_ = false;

      try
      {
        if (index.LookupMetadata(s, instanceId, MetadataType_Instance_IndexInSeries))
        {
          indexInSeries_ = boost::lexical_cast<size_t>(s);
          hasIndexInSeries_ = true;
        }
      }
      catch (boost::bad_lexical_cast&)
      {
      }
    }
コード例 #2
0
  static void ComputeSeriesCounters(DicomMap& result,
                                    ServerIndex& index,
                                    const std::string& series,
                                    const DicomMap& query)
  {
    std::list<std::string> instances;
    index.GetChildren(instances, series);

    if (query.HasTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES))
    {
      result.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES,
                      boost::lexical_cast<std::string>(instances.size()), false);
    }
  }
コード例 #3
0
void DatabaseWrapperBase::GetMainDicomTags(DicomMap& map,
        int64_t id)
{
    map.Clear();

    SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?");
    s.BindInt64(0, id);
    while (s.Step())
    {
        map.SetValue(s.ColumnInt(1),
                     s.ColumnInt(2),
                     s.ColumnString(3));
    }
}
コード例 #4
0
  static void ComputeStudyCounters(DicomMap& result,
                                   ServerContext& context,
                                   const std::string& study,
                                   const DicomMap& query)
  {
    ServerIndex& index = context.GetIndex();

    std::list<std::string> series;
    index.GetChildren(series, study);
    
    if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES))
    {
      result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES,
                      boost::lexical_cast<std::string>(series.size()), false);
    }

    if (query.HasTag(DICOM_TAG_MODALITIES_IN_STUDY))
    {
      std::set<std::string> values;
      ExtractTagFromMainDicomTags(values, index, DICOM_TAG_MODALITY, series, ResourceType_Series);
      StoreSetOfStrings(result, DICOM_TAG_MODALITIES_IN_STUDY, values);
    }

    if (!query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) &&
        !query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
    {
      return;
    }

    std::list<std::string> instances;
    GetChildren(instances, index, series);

    if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES))
    {
      result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES,
                      boost::lexical_cast<std::string>(instances.size()), false);
    }

    if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
    {
      if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
      {
        std::set<std::string> values;
        ExtractTagFromInstances(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
        StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
      }
      else
      {
        result.SetValue(DICOM_TAG_SOP_CLASSES_IN_STUDY, "", false);
        LOG(WARNING) << "The handling of \"SOP Classes in Study\" (0008,0062) "
                     << "in C-FIND requests is disabled";
      }
    }
  }
コード例 #5
0
  void LookupResource::ApplyLevel(SetOfResources& candidates,
                                  ResourceType level,
                                  IDatabaseWrapper& database) const
  {
    Levels::const_iterator it = levels_.find(level);
    if (it != levels_.end())
    {
      it->second->Apply(candidates, database);
    }

    if (level == ResourceType_Study &&
        modalitiesInStudy_.get() != NULL)
    {
      // There is a constraint on the "ModalitiesInStudy" DICOM
      // extension. Check out whether one child series has one of the
      // allowed modalities
      std::list<int64_t> allStudies, matchingStudies;
      candidates.Flatten(allStudies);
 
      for (std::list<int64_t>::const_iterator
             study = allStudies.begin(); study != allStudies.end(); ++study)
      {
        std::list<int64_t> childrenSeries;
        database.GetChildrenInternalId(childrenSeries, *study);

        for (std::list<int64_t>::const_iterator
               series = childrenSeries.begin(); series != childrenSeries.end(); ++series)
        {
          DicomMap tags;
          database.GetMainDicomTags(tags, *series);

          const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY);
          if (value != NULL &&
              !value->IsNull() &&
              !value->IsBinary())
          {
            if (modalitiesInStudy_->Match(value->GetContent()))
            {
              matchingStudies.push_back(*study);
              break;
            }
          }
        }
      }

      candidates.Intersect(matchingStudies);
    }
  }
コード例 #6
0
 static void ExtractTagFromMainDicomTags(std::set<std::string>& target,
                                         ServerIndex& index,
                                         const DicomTag& tag,
                                         const std::list<std::string>& resources,
                                         ResourceType level)
 {
   for (std::list<std::string>::const_iterator
          it = resources.begin(); it != resources.end(); ++it)
   {
     DicomMap tags;
     if (index.GetMainDicomTags(tags, *it, level, level) &&
         tags.HasTag(tag))
     {
       target.insert(tags.GetValue(tag).GetContent());
     }
   }
 }
コード例 #7
0
ファイル: DicomFindQuery.cpp プロジェクト: gbanana/orthanc
  bool DicomFindQuery::FilterMainDicomTags(const std::string& resourceId,
                                           ResourceType level,
                                           const DicomMap& mainTags) const
  {
    std::set<DicomTag> tags;
    mainTags.GetTags(tags);

    for (std::set<DicomTag>::const_iterator
           it = tags.begin(); it != tags.end(); ++it)
    {
      Constraints::const_iterator constraint = constraints_.find(*it);
      if (constraint != constraints_.end() &&
          !constraint->second->Apply(mainTags.GetValue(*it).AsString()))
      {
        return false;
      }
    }

    return true;
  }
コード例 #8
0
  static void AddAnswer(DicomFindAnswers& answers,
                        const Json::Value& resource,
                        const DicomArray& query)
  {
    DicomMap result;

    for (size_t i = 0; i < query.GetSize(); i++)
    {
      // Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052))
      if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL)
      {
        result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue());
      }
      else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET)
      {
      }
      else
      {
        std::string tag = query.GetElement(i).GetTag().Format();
        std::string value;
        if (resource.isMember(tag))
        {
          value = resource.get(tag, Json::arrayValue).get("Value", "").asString();
          result.SetValue(query.GetElement(i).GetTag(), value);
        }
        else
        {
          result.SetValue(query.GetElement(i).GetTag(), "");
        }
      }
    }

    if (result.GetSize() == 0)
    {
      LOG(WARNING) << "The C-FIND request does not return any DICOM tag";
    }
    else
    {
      answers.Add(result);
    }
  }
コード例 #9
0
TEST(DicomImageInformation, ExtractPixelFormat2)
{
  // Delphine CT
  DicomMap m;
  m.SetValue(DICOM_TAG_ROWS, "24");
  m.SetValue(DICOM_TAG_COLUMNS, "16");
  m.SetValue(DICOM_TAG_BITS_ALLOCATED, "16");
  m.SetValue(DICOM_TAG_SAMPLES_PER_PIXEL, "1");
  m.SetValue(DICOM_TAG_BITS_STORED, "16");
  m.SetValue(DICOM_TAG_HIGH_BIT, "15");
  m.SetValue(DICOM_TAG_PIXEL_REPRESENTATION, "1");
  m.SetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2");

  DicomImageInformation info(m);
  PixelFormat format;
  ASSERT_TRUE(info.ExtractPixelFormat(format));
  ASSERT_EQ(PixelFormat_SignedGrayscale16, format);
}
コード例 #10
0
TEST(DicomImageInformation, ExtractPixelFormat1)
{
  // Cardiac/MR*
  DicomMap m;
  m.SetValue(DICOM_TAG_ROWS, "24", false);
  m.SetValue(DICOM_TAG_COLUMNS, "16", false);
  m.SetValue(DICOM_TAG_BITS_ALLOCATED, "16", false);
  m.SetValue(DICOM_TAG_SAMPLES_PER_PIXEL, "1", false);
  m.SetValue(DICOM_TAG_BITS_STORED, "12", false);
  m.SetValue(DICOM_TAG_HIGH_BIT, "11", false);
  m.SetValue(DICOM_TAG_PIXEL_REPRESENTATION, "0", false);
  m.SetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2", false);

  DicomImageInformation info(m);
  PixelFormat format;
  ASSERT_TRUE(info.ExtractPixelFormat(format, false));
  ASSERT_EQ(PixelFormat_Grayscale16, format);
}
コード例 #11
0
ファイル: ServerToolbox.cpp プロジェクト: PACSinTERRA/orthanc
    void StoreMainDicomTags(IDatabaseWrapper& database,
                            int64_t resource,
                            ResourceType level,
                            const DicomMap& dicomSummary)
    {
      // WARNING: The database should be locked with a transaction!

      StoreIdentifiers(database, resource, level, dicomSummary);

      DicomMap tags;

      switch (level)
      {
        case ResourceType_Patient:
          dicomSummary.ExtractPatientInformation(tags);
          break;

        case ResourceType_Study:
          // Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6)
          dicomSummary.ExtractPatientInformation(tags);
          StoreMainDicomTagsInternal(database, resource, tags);

          dicomSummary.ExtractStudyInformation(tags);
          break;

        case ResourceType_Series:
          dicomSummary.ExtractSeriesInformation(tags);
          break;

        case ResourceType_Instance:
          dicomSummary.ExtractInstanceInformation(tags);
          break;

        default:
          throw OrthancException(ErrorCode_InternalError);
      }

      StoreMainDicomTagsInternal(database, resource, tags);
    }
コード例 #12
0
ファイル: ServerToolbox.cpp プロジェクト: PACSinTERRA/orthanc
 static std::string ValueAsString(const DicomMap& summary,
                                  const DicomTag& tag)
 {
   const DicomValue& value = summary.GetValue(tag);
   if (value.IsNull())
   {
     return "(null)";
   }
   else
   {
     return value.GetContent();
   }
 }
コード例 #13
0
  static void ComputePatientCounters(DicomMap& result,
                                     ServerIndex& index,
                                     const std::string& patient,
                                     const DicomMap& query)
  {
    std::list<std::string> studies;
    index.GetChildren(studies, patient);

    if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES))
    {
      result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES,
                      boost::lexical_cast<std::string>(studies.size()), false);
    }

    if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) &&
        !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
    {
      return;
    }

    std::list<std::string> series;
    GetChildren(series, index, studies);
    studies.clear();  // This information is useless below
    
    if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES))
    {
      result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES,
                      boost::lexical_cast<std::string>(series.size()), false);
    }

    if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
    {
      return;
    }

    std::list<std::string> instances;
    GetChildren(instances, index, series);

    if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
    {
      result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES,
                      boost::lexical_cast<std::string>(instances.size()), false);
    }
  }
コード例 #14
0
  static bool Match(const DicomMap& tags,
                    const DicomTag& tag,
                    const IFindConstraint& constraint)
  {
    const DicomValue* value = tags.TestAndGetValue(tag);

    if (value == NULL ||
        value->IsNull() ||
        value->IsBinary())
    {
      return false;
    }
    else
    {
      return constraint.Match(value->GetContent());
    }
  }
コード例 #15
0
  static bool TokenizeVector(std::vector<float>& result,
                             const DicomMap& map,
                             const DicomTag& tag,
                             unsigned int expectedSize)
  {
    const DicomValue* value = map.TestAndGetValue(tag);

    if (value == NULL ||
        value->IsNull() ||
        value->IsBinary())
    {
      return false;
    }
    else
    {
      return TokenizeVector(result, value->GetContent(), expectedSize);
    }
  }
コード例 #16
0
ファイル: ServerToolbox.cpp プロジェクト: PACSinTERRA/orthanc
    static void StoreIdentifiers(IDatabaseWrapper& database,
                                 int64_t resource,
                                 ResourceType level,
                                 const DicomMap& map)
    {
      const DicomTag* tags;
      size_t size;

      LoadIdentifiers(tags, size, level);

      for (size_t i = 0; i < size; i++)
      {
        const DicomValue* value = map.TestAndGetValue(tags[i]);
        if (value != NULL &&
            !value->IsNull() &&
            !value->IsBinary())
        {
          std::string s = NormalizeIdentifier(value->GetContent());
          database.SetIdentifierTag(resource, tags[i], s);
        }
      }
    }
コード例 #17
0
ファイル: DicomMapTests.cpp プロジェクト: dhanzhang/orthanc
TEST(DicomMap, FindTemplates)
{
  DicomMap m;

  DicomMap::SetupFindPatientTemplate(m);
  ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_ID));

  DicomMap::SetupFindStudyTemplate(m);
  ASSERT_TRUE(m.HasTag(DICOM_TAG_STUDY_INSTANCE_UID));
  ASSERT_TRUE(m.HasTag(DICOM_TAG_ACCESSION_NUMBER));

  DicomMap::SetupFindSeriesTemplate(m);
  ASSERT_TRUE(m.HasTag(DICOM_TAG_SERIES_INSTANCE_UID));

  DicomMap::SetupFindInstanceTemplate(m);
  ASSERT_TRUE(m.HasTag(DICOM_TAG_SOP_INSTANCE_UID));
}
コード例 #18
0
  static void StoreSetOfStrings(DicomMap& result,
                                const DicomTag& tag,
                                const std::set<std::string>& values)
  {
    bool isFirst = true;

    std::string s;
    for (std::set<std::string>::const_iterator
           it = values.begin(); it != values.end(); ++it)
    {
      if (isFirst)
      {
        isFirst = false;
      }
      else
      {
        s += "\\";
      }

      s += *it;
    }

    result.SetValue(tag, s, false);
  }
コード例 #19
0
TEST(ServerIndex, AttachmentRecycling)
{
  const std::string path = "UnitTestsStorage";

  Toolbox::RemoveFile(path + "/index");
  FilesystemStorage storage(path);
  DatabaseWrapper db;   // The SQLite DB is in memory
  ServerContext context(db);
  context.SetStorageArea(storage);
  ServerIndex& index = context.GetIndex();

  index.SetMaximumStorageSize(10);

  Json::Value tmp;
  index.ComputeStatistics(tmp);
  ASSERT_EQ(0, tmp["CountPatients"].asInt());
  ASSERT_EQ(0, boost::lexical_cast<int>(tmp["TotalDiskSize"].asString()));

  ServerIndex::Attachments attachments;

  std::vector<std::string> ids;
  for (int i = 0; i < 10; i++)
  {
    std::string id = boost::lexical_cast<std::string>(i);
    DicomMap instance;
    instance.SetValue(DICOM_TAG_PATIENT_ID, "patient-" + id);
    instance.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "study-" + id);
    instance.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "series-" + id);
    instance.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "instance-" + id);

    std::map<MetadataType, std::string> instanceMetadata;
    ServerIndex::MetadataMap metadata;
    ASSERT_EQ(StoreStatus_Success, index.Store(instanceMetadata, instance, attachments, "", metadata));
    ASSERT_EQ(2, instanceMetadata.size());
    ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_RemoteAet) != instanceMetadata.end());
    ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_ReceptionDate) != instanceMetadata.end());

    DicomInstanceHasher hasher(instance);
    ids.push_back(hasher.HashPatient());
    ids.push_back(hasher.HashStudy());
    ids.push_back(hasher.HashSeries());
    ids.push_back(hasher.HashInstance());
  }

  index.ComputeStatistics(tmp);
  ASSERT_EQ(10, tmp["CountPatients"].asInt());
  ASSERT_EQ(0, boost::lexical_cast<int>(tmp["TotalDiskSize"].asString()));

  for (size_t i = 0; i < ids.size(); i++)
  {
    FileInfo info(Toolbox::GenerateUuid(), FileContentType_Dicom, 1, "md5");
    index.AddAttachment(info, ids[i]);

    index.ComputeStatistics(tmp);
    ASSERT_GE(10, boost::lexical_cast<int>(tmp["TotalDiskSize"].asString()));
  }

  // Because the DB is in memory, the SQLite index must not have been created
  ASSERT_THROW(Toolbox::GetFileSize(path + "/index"), OrthancException);  

  context.Stop();
}
コード例 #20
0
ファイル: DicomMapTests.cpp プロジェクト: dhanzhang/orthanc
TEST(DicomMap, Tags)
{
  DicomMap m;
  ASSERT_FALSE(m.HasTag(DICOM_TAG_PATIENT_NAME));
  ASSERT_FALSE(m.HasTag(0x0010, 0x0010));
  m.SetValue(0x0010, 0x0010, "PatientName");
  ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_NAME));
  ASSERT_TRUE(m.HasTag(0x0010, 0x0010));

  ASSERT_FALSE(m.HasTag(DICOM_TAG_PATIENT_ID));
  m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID");
  ASSERT_TRUE(m.HasTag(0x0010, 0x0020));
  m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID2");
  ASSERT_EQ("PatientID2", m.GetValue(0x0010, 0x0020).AsString());

  m.Remove(DICOM_TAG_PATIENT_ID);
  ASSERT_THROW(m.GetValue(0x0010, 0x0020), OrthancException);

  std::auto_ptr<DicomMap> mm(m.Clone());
  ASSERT_EQ("PatientName", mm->GetValue(DICOM_TAG_PATIENT_NAME).AsString());  

  m.SetValue(DICOM_TAG_PATIENT_ID, "Hello");
  ASSERT_THROW(mm->GetValue(DICOM_TAG_PATIENT_ID), OrthancException);
  mm->CopyTagIfExists(m, DICOM_TAG_PATIENT_ID);
  ASSERT_EQ("Hello", mm->GetValue(DICOM_TAG_PATIENT_ID).AsString());  

  DicomNullValue v;
  ASSERT_TRUE(v.IsNull());
}
コード例 #21
0
ファイル: ServerToolbox.cpp プロジェクト: PACSinTERRA/orthanc
    void LogMissingRequiredTag(const DicomMap& summary)
    {
      std::string s, t;

      if (summary.HasTag(DICOM_TAG_PATIENT_ID))
      {
        if (t.size() > 0)
          t += ", ";
        t += "PatientID=" + ValueAsString(summary, DICOM_TAG_PATIENT_ID);
      }
      else
      {
        if (s.size() > 0)
          s += ", ";
        s += "PatientID";
      }

      if (summary.HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
      {
        if (t.size() > 0)
          t += ", ";
        t += "StudyInstanceUID=" + ValueAsString(summary, DICOM_TAG_STUDY_INSTANCE_UID);
      }
      else
      {
        if (s.size() > 0)
          s += ", ";
        s += "StudyInstanceUID";
      }

      if (summary.HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
      {
        if (t.size() > 0)
          t += ", ";
        t += "SeriesInstanceUID=" + ValueAsString(summary, DICOM_TAG_SERIES_INSTANCE_UID);
      }
      else
      {
        if (s.size() > 0)
          s += ", ";
        s += "SeriesInstanceUID";
      }

      if (summary.HasTag(DICOM_TAG_SOP_INSTANCE_UID))
      {
        if (t.size() > 0)
          t += ", ";
        t += "SOPInstanceUID=" + ValueAsString(summary, DICOM_TAG_SOP_INSTANCE_UID);
      }
      else
      {
        if (s.size() > 0)
          s += ", ";
        s += "SOPInstanceUID";
      }

      if (t.size() == 0)
      {
        LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)";
      }
      else
      {
        LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t;
      }
    }
コード例 #22
0
  bool OrthancFindRequestHandler::Handle(DicomFindAnswers& answers,
                                         const DicomMap& input,
                                         const std::string& callingAETitle)
  {
    /**
     * Ensure that the calling modality is known to Orthanc.
     **/

    RemoteModalityParameters modality;

    if (!Configuration::LookupDicomModalityUsingAETitle(modality, callingAETitle))
    {
      throw OrthancException("Unknown modality");
    }

    // ModalityManufacturer manufacturer = modality.GetManufacturer();

    bool caseSensitivePN = Configuration::GetGlobalBoolParameter("CaseSensitivePN", false);


    /**
     * Retrieve the query level.
     **/

    const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
    if (levelTmp == NULL) 
    {
      throw OrthancException(ErrorCode_BadRequest);
    }

    ResourceType level = StringToResourceType(levelTmp->AsString().c_str());

    if (level != ResourceType_Patient &&
        level != ResourceType_Study &&
        level != ResourceType_Series &&
        level != ResourceType_Instance)
    {
      throw OrthancException(ErrorCode_NotImplemented);
    }


    DicomArray query(input);
    LOG(INFO) << "DICOM C-Find request at level: " << EnumerationToString(level);

    for (size_t i = 0; i < query.GetSize(); i++)
    {
      if (!query.GetElement(i).GetValue().IsNull())
      {
        LOG(INFO) << "  " << query.GetElement(i).GetTag()
                  << "  " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
                  << " = " << query.GetElement(i).GetValue().AsString();
      }
    }


    /**
     * Build up the query object.
     **/

    CFindQuery findQuery(answers, context_.GetIndex(), query);
    findQuery.SetLevel(level);
        
    for (size_t i = 0; i < query.GetSize(); i++)
    {
      const DicomTag tag = query.GetElement(i).GetTag();

      if (query.GetElement(i).GetValue().IsNull() ||
          tag == DICOM_TAG_QUERY_RETRIEVE_LEVEL ||
          tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
      {
        continue;
      }

      std::string value = query.GetElement(i).GetValue().AsString();
      if (value.size() == 0)
      {
        // An empty string corresponds to a "*" wildcard constraint, so we ignore it
        continue;
      }

      if (tag == DICOM_TAG_MODALITIES_IN_STUDY)
      {
        findQuery.SetModalitiesInStudy(value);
      }
      else
      {
        findQuery.SetConstraint(tag, value, caseSensitivePN);
      }
    }


    /**
     * Run the query.
     **/

    ResourceFinder finder(context_);

    switch (level)
    {
      case ResourceType_Patient:
      case ResourceType_Study:
      case ResourceType_Series:
        finder.SetMaxResults(maxResults_);
        break;

      case ResourceType_Instance:
        finder.SetMaxResults(maxInstances_);
        break;

      default:
        throw OrthancException(ErrorCode_InternalError);
    }

    std::list<std::string> tmp;
    bool finished = finder.Apply(tmp, findQuery);

    LOG(INFO) << "Number of matching resources: " << tmp.size();

    return finished;
  }
コード例 #23
0
  static void AddAnswer(DicomFindAnswers& answers,
                        const Json::Value& resource,
                        const DicomArray& query,
                        const std::list<DicomTag>& sequencesToReturn,
                        const DicomMap* counters)
  {
    DicomMap result;

    for (size_t i = 0; i < query.GetSize(); i++)
    {
      if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL)
      {
        // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052))
        result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue());
      }
      else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET)
      {
        // Do not include the encoding, this is handled by class ParsedDicomFile
      }
      else
      {
        std::string tag = query.GetElement(i).GetTag().Format();
        std::string value;
        if (resource.isMember(tag))
        {
          value = resource.get(tag, Json::arrayValue).get("Value", "").asString();
          result.SetValue(query.GetElement(i).GetTag(), value, false);
        }
        else
        {
          result.SetValue(query.GetElement(i).GetTag(), "", false);
        }
      }
    }

    if (counters != NULL)
    {
      DicomArray tmp(*counters);
      for (size_t i = 0; i < tmp.GetSize(); i++)
      {
        result.SetValue(tmp.GetElement(i).GetTag(), tmp.GetElement(i).GetValue().GetContent(), false);
      }
    }

    if (result.GetSize() == 0 &&
        sequencesToReturn.empty())
    {
      LOG(WARNING) << "The C-FIND request does not return any DICOM tag";
    }
    else if (sequencesToReturn.empty())
    {
      answers.Add(result);
    }
    else
    {
      ParsedDicomFile dicom(result);

      for (std::list<DicomTag>::const_iterator tag = sequencesToReturn.begin();
           tag != sequencesToReturn.end(); ++tag)
      {
        const Json::Value& source = resource[tag->Format()];

        if (source.type() == Json::objectValue &&
            source.isMember("Type") &&
            source.isMember("Value") &&
            source["Type"].asString() == "Sequence" &&
            source["Value"].type() == Json::arrayValue)
        {
          Json::Value content = Json::arrayValue;

          for (Json::Value::ArrayIndex i = 0; i < source["Value"].size(); i++)
          {
            Json::Value item;
            Toolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short);
            content.append(item);
          }

          dicom.Replace(*tag, content, false, DicomReplaceMode_InsertIfAbsent);
        }
      }

      answers.Add(dicom);
    }
  }
コード例 #24
0
  bool OrthancFindRequestHandler::ApplyLuaFilter(DicomMap& target,
                                                 const DicomMap& source,
                                                 const std::string& remoteIp,
                                                 const std::string& remoteAet,
                                                 const std::string& calledAet)
  {
    Json::Value output;

    {
      LuaScripting::Locker locker(context_.GetLua());
      static const char* NAME = "IncomingFindRequestFilter";
      
      if (!locker.GetLua().IsExistingFunction(NAME))
      {
        return false;
      }

      Json::Value tmp = Json::objectValue;
      DicomArray a(source);

      for (size_t i = 0; i < a.GetSize(); i++)
      {
        const DicomValue& v = a.GetElement(i).GetValue();
        std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent();
        tmp[a.GetElement(i).GetTag().Format()] = s;
      }

      Json::Value origin = Json::objectValue;
      origin["RemoteIp"] = remoteIp;
      origin["RemoteAet"] = remoteAet;
      origin["CalledAet"] = calledAet;

      LuaFunctionCall call(locker.GetLua(), NAME);
      call.PushJson(tmp);
      call.PushJson(origin);

      call.ExecuteToJson(output, true);
    }

    // The Lua context is released at this point

    if (output.type() != Json::objectValue)
    {
      LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
      throw OrthancException(ErrorCode_LuaBadOutput);
    }

    Json::Value::Members members = output.getMemberNames();

    for (size_t i = 0; i < members.size(); i++)
    {
      if (output[members[i]].type() != Json::stringValue)
      {
        LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
        throw OrthancException(ErrorCode_LuaBadOutput);
      }

      DicomTag tag(FromDcmtkBridge::ParseTag(members[i]));
      target.SetValue(tag, output[members[i]].asString(), false);
    }

    return true;
  }