/** * Lo scopo di questa operazione è quella di scaricare le foto * dalla flash card all'hard disk locale il più velocemente * possibile. In questo modo posso congedare il fotografo che * sta aspettando. Durante questa fase, non ho feedback con l'utente. * Terminato lo scarico, allora posso muovere il file nella giusta * cartella di destinazione, scrivendo nel database e sollevando gli * eventi per poter visualizzare le foto. */ public void scarica(ParamScarica paramScarica) { _paramScarica = paramScarica; seNonPossoScaricareSpaccati(); // Se per sbaglio ho ancora un worker aperto, lo chiudo chiudiWorker(); // --- Pubblico un messaggio di inizio scaricamento foto ScaricoFotoMsg scaricoFotoMsg = new ScaricoFotoMsg(this, "Inizio Scarico Foto"); scaricoFotoMsg.esitoScarico = new EsitoScarico { riscontratiErrori = false }; scaricoFotoMsg.fase = FaseScaricoFoto.InizioScarico; scaricoFotoMsg.sorgente = _paramScarica.cartellaSorgente != null ? _paramScarica.cartellaSorgente : _paramScarica.nomeFileSingolo; scaricoFotoMsg.showInStatusBar = true; pubblicaMessaggio(scaricoFotoMsg); // --- // Creo il worker che copierà le foto in background _copiaImmaginiWorker = new CopiaImmaginiWorker(paramScarica, elaboraFotoAcquisite); // Lancio il worker che scarica ed elabora le foto. bool usaThreadSeparato = String.IsNullOrEmpty(paramScarica.nomeFileSingolo); if (usaThreadSeparato) { _copiaImmaginiWorker.Start(); } else { _copiaImmaginiWorker.StartSingleThread(); } statoScarica = StatoScarica.Scaricamento; }
/// <summary> /// Il parametro passato "tempoScarico" deve essere ribaltato su tutte le foto, perché /// serve a creare una relazione implicita 1-n tra lo ScaricoCard e Fotografia /// </summary> /// <param name="tempoScarico"></param> public void elabora(DateTime tempoScarico) { _giornale.Debug("Inizio ad elaborare le foto acquisite"); // carico il fotografo che rimane uguale per tutta questa sessione di elaborazione LumenEntities objContext = UnitOfWorkScope.currentDbContext; _fotografo = objContext.Fotografi.Single <Fotografo>(ff => ff.id == _paramScarica.flashCardConfig.idFotografo); // carico l'evento che rimane uguale per tutta questa sessione di elaborazione if (_paramScarica.flashCardConfig.idEvento != null && _paramScarica.flashCardConfig.idEvento != Guid.Empty) { _evento = objContext.Eventi.SingleOrDefault(e => e.id == _paramScarica.flashCardConfig.idEvento); } _giornale.Debug("Sto per lavorare le " + _listaFiles.Count + " foto appena acquisite di " + _fotografo.id); int ultimoNumFoto = NumeratoreFotogrammi.incrementaNumeratoreFoto(_listaFiles.Count); contaAggiunteDb = 0; ScaricoFotoMsg scaricoFotoMsg = new ScaricoFotoMsg(this, "Notifica progresso"); scaricoFotoMsg.fase = FaseScaricoFoto.Provinatura; scaricoFotoMsg.esitoScarico = new EsitoScarico(); scaricoFotoMsg.esitoScarico.totFotoScaricate = _listaFiles.Count; scaricoFotoMsg.sorgente = _paramScarica.cartellaSorgente != null ? _paramScarica.cartellaSorgente : _paramScarica.nomeFileSingolo; scaricoFotoMsg.showInStatusBar = false; IList <Fotografia> fotoDaEsaminare = null; if (_paramScarica.ricercaBarCode) { fotoDaEsaminare = new List <Fotografia>(); } foreach (FileInfo fileInfo in _listaFiles) { // Eseguo una transazione per ogni foto, in questo modo sono sicuro che tutto quello che posso buttare dentro, ci va. using (TransactionScope transaction = new TransactionScope()) { try { int proxNum = 1 + contaAggiunteDb + ultimoNumFoto; Fotografia foto = aggiungiFoto(fileInfo, proxNum, tempoScarico); // // --- eventuale maschera automatica if (_paramScarica.mascheraAuto != null) { // Uso la maschera nella sua dimensione naturale Imaging.Correzioni.Mascheratura mascheraratura = new Imaging.Correzioni.Mascheratura { nome = _paramScarica.mascheraAuto.nomeFile, width = _paramScarica.mascheraAuto.imgOriginale.ww, height = _paramScarica.mascheraAuto.imgOriginale.hh }; fotoRitoccoSrv.addCorrezione(foto, mascheraratura, false); } // Mark the transaction as complete. transaction.Complete(); // Incremento qui il contatore perché in caso di eccezione, voglio che non si incrementi ++contaAggiunteDb; _giornale.Debug("Inizio Provinatura immagine " + fileInfo.FullName); AiutanteFoto.creaProvinoFoto(fileInfo.FullName, foto); _giornale.Debug("Fine Provinatura immagine "); // Libero la memoria occupata dalle immagini, altrimenti esplode. AiutanteFoto.disposeImmagini(foto, IdrataTarget.Tutte); if (_paramScarica.ricercaBarCode) { fotoDaEsaminare.Add(foto); } // Se lavoro con una singola foto, allora lancio l'evento che mi dice che è pronta. if (String.IsNullOrEmpty(_paramScarica.nomeFileSingolo) == false) { // Quando sono a posto con la foto, sollevo un evento per avvisare tutti // Siccome questa operazione è un pò onerosa, per il momento la abilito // soltanto sulla singola foto. Se ne scarico 1000 di foto, non voglio lanciare 1000 eventi!!! NuovaFotoMsg msg = new NuovaFotoMsg(this, foto); LumenApplication.Instance.bus.Publish(msg); } _giornale.Debug("ok nuova foto provinata e inserita nel db: " + foto); if (contaAggiunteDb % 20 == 0) { scaricoFotoMsg.esitoScarico.totFotoProvinateProg = contaAggiunteDb; LumenApplication.Instance.bus.Publish(scaricoFotoMsg); } } catch (Exception ee) { transaction.Dispose(); _giornale.Error("Errore elaborazione foto. Viene ignorata " + fileInfo, ee); } } } if (_paramScarica.ricercaBarCode) { barCodeSrv.scan(fotoDaEsaminare); } if (contaAggiunteDb != 0) { scaricoFotoMsg.esitoScarico.totFotoProvinateProg = contaAggiunteDb; scaricoFotoMsg.esitoScarico.totFotoProvinate = contaAggiunteDb; LumenApplication.Instance.bus.Publish(scaricoFotoMsg); } _giornale.Info("Terminato di lavorare " + _listaFiles.Count + " foto appena acquisite"); incrementaTotaleFotoScaricate(tempoScarico); }
private void elaboraFotoAcquisite(EsitoScarico esitoScarico) { _giornale.Debug("Inizio elaboraFotoAcquisite()"); StringBuilder msg = new StringBuilder(); if (esitoScarico.riscontratiErrori) { msg.AppendFormat("Errore in acquisizione {0} foto. Verificare!", esitoScarico.totFotoCopiateOk); } else { msg.AppendFormat("Scaricate OK {0} foto.", +esitoScarico.totFotoCopiateOk); } msg.Append(" Togliere la card"); ScaricoFotoMsg scaricoFotoMsg = new ScaricoFotoMsg(this, msg.ToString()); scaricoFotoMsg.esitoScarico = esitoScarico; scaricoFotoMsg.esito = esitoScarico.riscontratiErrori ? Esito.Errore : Esito.Ok; // Finito: genero un evento per notificare che l'utente può togliere la flash card. scaricoFotoMsg.fase = FaseScaricoFoto.FineScarico; scaricoFotoMsg.sorgente = _paramScarica.cartellaSorgente != null ? _paramScarica.cartellaSorgente : _paramScarica.nomeFileSingolo; scaricoFotoMsg.showInStatusBar = true; // battezzo la flashcard al fotografo corrente battezzaFlashCard(_paramScarica); // Se il drive che ho appena scaricato è rimovibile, allora lo smonto // Richiesta di Ciccio del 29-03-2018 non smontiamo piu la card // smontaSeRimovibile(); // Rendo pubblico l'esito dello scarico in modo che la UI possa notificare l'utente di togliere // la flash card. /* * per l'onride mi serve che lanci il msg anche su un solo file * però mi pare che nessuno utilizzi il modo singolo. quindi lo pubblico sempre * * if( _paramScarica.nomeFileSingolo == null && _paramScarica.cartellaSorgente != null ) */ pubblicaMessaggio(scaricoFotoMsg); _giornale.Debug("Scaricate " + esitoScarico.totFotoCopiateOk + " foto. Si può togliere la card"); // -- inizio elaborazione ElaboratoreFotoAcquisite elab = new ElaboratoreFotoAcquisite(esitoScarico.fotoDaLavorare, _paramScarica); statoScarica = StatoScarica.Provinatura; elab.elabora(esitoScarico.tempo); _giornale.Debug("Elaborazione terminata. Inserite " + elab.contaAggiunteDb + " foto nel database"); statoScarica = StatoScarica.Idle; // Rendo pubblico l'esito dell'elaborazione così che si può aggiornare la libreria. scaricoFotoMsg.esitoScarico.totFotoProvinate = elab.contaAggiunteDb; if (scaricoFotoMsg.esitoScarico.totFotoProvinate != scaricoFotoMsg.esitoScarico.totFotoScaricate) { scaricoFotoMsg.esitoScarico.riscontratiErrori = true; } scaricoFotoMsg.fase = FaseScaricoFoto.FineLavora; scaricoFotoMsg.descrizione = "Provinatura foto terminata. Inserite " + elab.contaAggiunteDb + " foto nel database"; scaricoFotoMsg.showInStatusBar = true; pubblicaMessaggio(scaricoFotoMsg); // Chiudo il worker che ha finito il suo lavoro // _copiaImmaginiWorker.Stop(); // Faccio un controllo: Se le foto scaricate non coincidono con quelle elaborate (ovvero scritte nel db e provinate) // Allora c'è stato un problema. Devo avvisare l'utente di ricostruire il database bool problemiInVista = (esitoScarico.riscontratiErrori || esitoScarico.totFotoCopiateOk != elab.contaAggiunteDb); if (problemiInVista) { // TODO stampare nel log tutto l'oggetto EsitoScarico _giornale.Warn(String.Format("Riscontrata incongruenza database. copiate={0} elab={1}", esitoScarico.totFotoCopiateOk, elab.contaAggiunteDb)); RilevataInconsistenzaDatabaseMsg inconsistenzaMsg = new RilevataInconsistenzaDatabaseMsg(this); inconsistenzaMsg.descrizione = "Inconsistenza database. Lanciare ricostruzione!"; inconsistenzaMsg.showInStatusBar = true; inconsistenzaMsg.giornataDaVerificare = LumenApplication.Instance.stato.giornataLavorativa; pubblicaMessaggio(inconsistenzaMsg); } }
/** * Processo reale di trasferimento immagini */ protected override void Work() { int conta = 0; _giornale.Debug("Inizio a trasferire le foto da " + _paramScarica.cartellaSorgente); string nomeDirDest = calcolaCartellaDestinazione(); // Creo la cartella che conterrà le foto Directory.CreateDirectory(nomeDirDest); // Creo la cartella che conterrà i provini PathUtil.creaCartellaProvini(new FileInfo(nomeDirDest)); _esitoScarico = new EsitoScarico(); ScaricoFotoMsg scaricoFotoMsg = new ScaricoFotoMsg(this, "Notifica progresso"); scaricoFotoMsg.fase = FaseScaricoFoto.Scaricamento; scaricoFotoMsg.esitoScarico = _esitoScarico; scaricoFotoMsg.sorgente = _paramScarica.cartellaSorgente != null ? _paramScarica.cartellaSorgente : _paramScarica.nomeFileSingolo; scaricoFotoMsg.showInStatusBar = false; try { if (_paramScarica.nomeFileSingolo != null) { // Lavoro un solo file che mi è stato indicato. Serve per creare una maschera quando lavoro con le cornici. if (scaricaAsincronoUnFile(_paramScarica.nomeFileSingolo, nomeDirDest)) { ++conta; if (conta % 20 == 0) { scaricoFotoMsg.esitoScarico.totFotoScaricateProg = conta; LumenApplication.Instance.bus.Publish(scaricoFotoMsg); } } else { // La copia di questo file non è andata a buon fine _esitoScarico.riscontratiErrori = true; } } else { // Faccio giri diversi per i vari formati grafici che sono indicati nella configurazione (jpg, tif) string[] estensioni = Configurazione.UserConfigLumen.estensioniGrafiche.Split(';'); foreach (string estensione in estensioni) { string[] files = Directory.GetFiles(_paramScarica.cartellaSorgente, searchPattern: "*" + estensione, searchOption: SearchOption.AllDirectories); // trasferisco tutti i files elencati foreach (string nomeFileSrc in files) { if (scaricaAsincronoUnFile(nomeFileSrc, nomeDirDest)) { ++conta; if (conta % 20 == 0) { scaricoFotoMsg.esitoScarico.totFotoScaricateProg = conta; LumenApplication.Instance.bus.Publish(scaricoFotoMsg); } } else { // La copia di questo file non è andata a buon fine _esitoScarico.riscontratiErrori = true; } } } } } catch (Exception qq) { // Se casco qui, probabilmente è perché è stata sfilata la memorycard prima che sia completato lo scarico. _esitoScarico.riscontratiErrori = true; _giornale.Error("Errore imprevisto durante scarico card", qq); } if (conta != 0) { scaricoFotoMsg.esitoScarico.totFotoScaricate = conta; scaricoFotoMsg.esitoScarico.totFotoScaricateProg = conta; LumenApplication.Instance.bus.Publish(scaricoFotoMsg); } // Nel log scrivo anche il tempo che ci ho messo a scaricare le foto. Mi servirà per profilare TimeSpan tempoImpiegato = DateTime.Now.Subtract(_esitoScarico.tempo); _giornale.Info("Terminato trasferimento di " + conta + " foto. Tempo impiegato = " + tempoImpiegato); // Deve essere già aperto using (new UnitOfWorkScope(true)) { // ::: Ultima fase eleboro le foto memorizzando nel db e creando le dovute cache _elaboraImmaginiAcquisiteCallback.Invoke(_esitoScarico); } _giornale.Debug("Terminato background worker per copia files"); }