func ProcessOneZipFile(inputPath, outputPath, zipName string, dicomList []string, includeOverlay bool) error {

	path := filepath.Join(inputPath, zipName)
	if strings.HasPrefix(inputPath, "gs://") {
		path = inputPath
		if !strings.HasSuffix(path, "/") {
			path += "/"
		}
		path += zipName
	}

	// Note: uses global client, which is OK for concurrent use
	f, nBytes, err := bulkprocess.MaybeOpenFromGoogleStorage(path, client)
	if err != nil {
		return fmt.Errorf("ProcessOneZipFile fatal error (terminating on zip %s): %v", zipName, err)
	}
	defer f.Close()

	// Whether it is efficient to ingest the entire zip file or not depends in
	// part on how many files within the zip are being read out, how big the
	// files are, and what kind of connection they are being read over. This is
	// optimized for UK Biobank MRIs where the zip files are generally < 100MB.
	// Reading these from disk is fast, but seeking over the network is much
	// slower (~60x slower over a 500 mbit 20ms latency TCP/IP connection than
	// from an SSD). Because of GCSFuse, it's not always clear whether these
	// files are being read over the network based on path alone. Here, if we
	// are requesting more than one file from a zip, we ingest the full file
	// into RAM before operating on it.
	var readerAt io.ReaderAt = f
	if len(dicomList) > 1 {
		b, err := ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		readerAt = bytes.NewReader(b)
	}

	// Open the zip once so we don't have to reopen/reclose for every dicom
	rc, err := zip.NewReader(readerAt, nBytes)
	if err != nil {
		return err
	}

	dicomMap := make(map[string]struct{})
	for _, dicomName := range dicomList {
		dicomMap[dicomName] = struct{}{}
	}

	// Make only one pass over the Zip
	for _, fileInZip := range rc.File {

		// Skip irrelevant files
		if _, exists := dicomMap[fileInZip.Name]; !exists {
			continue
		}

		// The file is a desired DICOM. Parse it and extract its image.
		err := func(fileInZip *zip.File) error {

			dicomReader, err := fileInZip.Open()
			if err != nil {
				return err
			}
			defer dicomReader.Close()

			// Buffering again here seems to speed things up about 10% locally.
			var dicomReaderBuffered io.Reader = dicomReader
			dicomReaderBytes, err := ioutil.ReadAll(dicomReader)
			if err != nil {
				return err
			}
			dicomReaderBuffered = bytes.NewReader(dicomReaderBytes)

			img, err := bulkprocess.ExtractDicomFromReader(dicomReaderBuffered, int64(fileInZip.UncompressedSize64), includeOverlay)
			if err != nil {
				return err
			}

			return imgToPNG(img, outputPath, fileInZip.Name)
		}(fileInZip)

		// Since we want to continue processing the zip even if one of its
		// dicoms was bad, simply log the error. However, if the underlying
		// file system is unreliable, we should then exit.
		if err != nil && strings.Contains(err.Error(), "input/output error") {

			// If we had an error due to an unreliable filesystem, we need to
			// fail the whole job or we will end up with unreliable or missing
			// data.
			return fmt.Errorf("ProcessOneZipFile fatal error (terminating on dicom %s in zip %s): %v", fileInZip.Name, zipName, err)

		} else if err != nil {

			// Non-i/o errors usually indicate that this is just a bad internal
			// file that will never be readable, in which case we should move on
			// rather than quitting.
			log.Printf("ProcessOneZipFile error (skipping dicom %s in zip %s): %v\n", fileInZip.Name, zipName, err)

		}
	}

	return nil
}
// ProcessOneZipFile prints out PNGs for all DICOM images within a zip file that
// are found in dicomList. TODO: handle errors more thoughtfully, e.g., with an
// error channel.
ProcessOneZipFile prints out PNGs for all DICOM images within a zip file that
are found in dicomList. TODO: handle errors more thoughtfully, e.g., with an
error channel.
// ProcessOneZipFile prints out PNGs for all DICOM images within a zip file that // are found in dicomList . TODO : handle errors more thoughtfully e . g . with an // error channel .
func ProcessOneZipFile(inputPath, outputPath, zipName string, dicomList []string, includeOverlay bool) error {
	path := filepath.Join(inputPath, zipName)
	if strings.HasPrefix(inputPath, "gs://") {
		path = inputPath
		if !strings.HasSuffix(path, "/") {
			path += "/"
		}
		path += zipName
	}
	f, nBytes, err := bulkprocess.MaybeOpenFromGoogleStorage(path, client)
	if err != nil {
		return fmt.Errorf("ProcessOneZipFile fatal error (terminating on zip %s): %v", zipName, err)
	}
	defer f.Close()
	var readerAt io.ReaderAt = f
	if len(dicomList) > 1 {
		b, err := ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		readerAt = bytes.NewReader(b)
	}
	rc, err := zip.NewReader(readerAt, nBytes)
	if err != nil {
		return err
	}
	dicomMap := make(map[string]struct{})
	for _, dicomName := range dicomList {
		dicomMap[dicomName] = struct{}{}
	}
	for _, fileInZip := range rc.File {
		if _, exists := dicomMap[fileInZip.Name]; !exists {
			continue
		}
		err := func(fileInZip *zip.File) error {
			dicomReader, err := fileInZip.Open()
			if err != nil {
				return err
			}
			defer dicomReader.Close()
			var dicomReaderBuffered io.Reader = dicomReader
			dicomReaderBytes, err := ioutil.ReadAll(dicomReader)
			if err != nil {
				return err
			}
			dicomReaderBuffered = bytes.NewReader(dicomReaderBytes)
			img, err := bulkprocess.ExtractDicomFromReader(dicomReaderBuffered, int64(fileInZip.UncompressedSize64), includeOverlay)
			if err != nil {
				return err
			}
			return imgToPNG(img, outputPath, fileInZip.Name)
		}(fileInZip)
		if err != nil && strings.Contains(err.Error(), "input/output error") {
			return fmt.Errorf("ProcessOneZipFile fatal error (terminating on dicom %s in zip %s): %v", fileInZip.Name, zipName, err)
		} else if err != nil {
			log.Printf("ProcessOneZipFile error (skipping dicom %s in zip %s): %v\n", fileInZip.Name, zipName, err)
		}
	}
	return nil
}
func ProcessOneZipFile ( inputPath , outputPath , zipName string , dicomList [ ] string , includeOverlay bool ) error { path := filepath . Join ( inputPath , zipName ) if strings . HasPrefix ( inputPath , " " ) { path = inputPath if ! strings . HasSuffix ( path , " " ) { path += " " } path += zipName } f , nBytes , err := bulkprocess . MaybeOpenFromGoogleStorage ( path , client ) if err != nil { return fmt . Errorf ( " " , zipName , err ) } defer f . Close ( ) var readerAt io . ReaderAt = f if len ( dicomList ) > 1 { b , err := ioutil . ReadAll ( f ) if err != nil { return err } readerAt = bytes . NewReader ( b ) } rc , err := zip . NewReader ( readerAt , nBytes ) if err != nil { return err } dicomMap := make ( map [ string ] struct { } ) for _ , dicomName := range dicomList { dicomMap [ dicomName ] = struct { } { } } for _ , fileInZip := range rc . File { if _ , exists := dicomMap [ fileInZip . Name ] ; ! exists { continue } err := func ( fileInZip * zip . File ) error { dicomReader , err := fileInZip . Open ( ) if err != nil { return err } defer dicomReader . Close ( ) var dicomReaderBuffered io . Reader = dicomReader dicomReaderBytes , err := ioutil . ReadAll ( dicomReader ) if err != nil { return err } dicomReaderBuffered = bytes . NewReader ( dicomReaderBytes ) img , err := bulkprocess . ExtractDicomFromReader ( dicomReaderBuffered , int64 ( fileInZip . UncompressedSize64 ) , includeOverlay ) if err != nil { return err } return imgToPNG ( img , outputPath , fileInZip . Name ) } ( fileInZip ) if err != nil && strings . Contains ( err . Error ( ) , " " ) { return fmt . Errorf ( " " , fileInZip . Name , zipName , err ) } else if err != nil { log . Printf ( " \n " , fileInZip . Name , zipName , err ) } } return nil }
ProcessOneZipFile prints out PNGs for all DICOM images within a zip file that
are found in dicomList.
ProcessOneZipFile prints out PNGs for all DICOM images within a zip file that are found in dicomList .
// Note: uses global client, which is OK for concurrent use // Whether it is efficient to ingest the entire zip file or not depends in // part on how many files within the zip are being read out, how big the // files are, and what kind of connection they are being read over. This is // optimized for UK Biobank MRIs where the zip files are generally < 100MB. // Reading these from disk is fast, but seeking over the network is much // slower (~60x slower over a 500 mbit 20ms latency TCP/IP connection than // from an SSD). Because of GCSFuse, it's not always clear whether these // files are being read over the network based on path alone. Here, if we // are requesting more than one file from a zip, we ingest the full file // into RAM before operating on it. // Open the zip once so we don't have to reopen/reclose for every dicom // Make only one pass over the Zip // Skip irrelevant files // The file is a desired DICOM. Parse it and extract its image. // Buffering again here seems to speed things up about 10% locally. // Since we want to continue processing the zip even if one of its // dicoms was bad, simply log the error. However, if the underlying // file system is unreliable, we should then exit. // If we had an error due to an unreliable filesystem, we need to // fail the whole job or we will end up with unreliable or missing // data. // Non-i/o errors usually indicate that this is just a bad internal // file that will never be readable, in which case we should move on // rather than quitting.