public void OnNext(FotoModificateMsg fmMsg)
        {
            if (slideShow == null)
            {
                return;
            }

            foreach (Fotografia modificata in fmMsg.fotos)
            {
                int pos = slideShow.slides.IndexOf(modificata);
                if (pos > 0)
                {
                    AiutanteFoto.disposeImmagini(slideShow.slides[pos], IdrataTarget.Provino);

                    // Se la foto è stata modificata, allora mi copio le correzioni.
                    slideShow.slides[pos].correzioniXml = modificata.correzioniXml;
                    // Se ho a  disposizione l'immagine del provino, me la copio, altrimenti me la rileggo da disco.
                    if (modificata.imgProvino != null)
                    {
                        slideShow.slides[pos].imgProvino = (Digiphoto.Lumen.Imaging.IImmagine)modificata.imgProvino;
                    }
                    else
                    {
                        AiutanteFoto.idrataImmaginiFoto(slideShow.slides[pos], IdrataTarget.Provino, true);
                    }
                }
            }
        }
Exemple #2
0
        private byte[] getImage(Guid fotografiaId, IdrataTarget quale)
        {
            byte[] bytes = null;

            using (new UnitOfWorkScope()) {
                var srv = LumenApplication.Instance.getServizioAvviato <IEntityRepositorySrv <Fotografia> >();

                Fotografia fotografia = srv.getById(fotografiaId);

                string nomeFileImg;

                // Qui faccio una piccola miglioria: Se l'immagine risultante ha delle correzioni non ancora applicate, le applico adesso.
                if (quale == IdrataTarget.Risultante)
                {
                    nomeFileImg = AiutanteFoto.idrataImmagineDaStampare(fotografia);
                }
                else
                {
                    nomeFileImg = AiutanteFoto.idrataImmaginiFoto(fotografia, quale);
                }

                bytes = File.ReadAllBytes(nomeFileImg);

                AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Tutte);
            }

            return(bytes);
        }
        /// <summary>
        /// Elimina tutte le Correzioni da una foto e quindi ricrea il provino
        /// </summary>
        public void tornaOriginale(Fotografia fotografia, bool salvare)
        {
            fotografia.correzioniXml = null;

            // Rimuovo anche eventuale file su disco
            string nomeFileRis = PathUtil.nomeCompletoRisultante(fotografia);

            if (File.Exists(nomeFileRis))
            {
                File.Delete(nomeFileRis);
            }

            // Rilascio memoria
            AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Tutte);

            AiutanteFoto.creaProvinoFoto(fotografia);

            // Le due foto grandi le rilascio per non intasare la memoria qualora questo metodo è chiamato più volte
            AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Originale);
            AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Risultante);

            if (salvare)
            {
                Fotografia f = fotografia;
                fotografieRepositorySrv.update(ref f, true);
                fotografieRepositorySrv.saveChanges();                  // Persisto nel db le modifiche

                // Devo informate tutti che questa foto è cambiata
                FotoModificateMsg msg = new FotoModificateMsg(this, fotografia);
                pubblicaMessaggio(msg);
            }
        }
        /// <summary>
        /// Uso tutti try-catch perché è importante che io arrivi a fare la dispose del DbContext,
        /// altrimenti mi rimangono le entità tracciate.
        /// </summary>
        public void Dispose()
        {
            // Se ho delle fotografie caricate, rilascio le immagini
            if (carrello != null && carrello.righeCarrello != null)
            {
                foreach (RigaCarrello riga in carrello.righeCarrello)
                {
                    try {
                        AiutanteFoto.disposeImmagini(riga.fotografia);
                    } catch (Exception) {
                    }
                }
            }

            // Se il carrello è stato modificato nel db o aggiunto al db ma non ancora committato, allora devo "tornare indietro"
            if (carrello != null && isCarrelloTransient == false)
            {
                try {
                    OrmUtil.rinuncioAlleModifiche(carrello, mioDbContext);
                } catch (Exception) {
                }

                carrello = null;
            }

            isCarrelloModificato = false;

            // Distruggo anche il contesto. In questo modo riparto pulito per il prossimo carrello, ma sopattutto devo rilasciare le entità che sono "tracciate" da questo context
            this.mioDbContext.Dispose();
            this.mioDbContext = null;
        }
        public void tornaOriginale(IEnumerable <Fotografia> fotografie, bool salvare)
        {
            foreach (Fotografia fotografia in fotografie)
            {
                fotografia.correzioniXml = null;

                // Rimuovo anche eventuale file su disco
                string nomeFileRis = PathUtil.nomeCompletoRisultante(fotografia);
                if (File.Exists(nomeFileRis))
                {
                    File.Delete(nomeFileRis);
                }

                // Rilascio memoria
                AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Tutte);

                if (salvare)
                {
                    Fotografia f = fotografia;
                    fotografieRepositorySrv.update(ref f, true);
                    fotografieRepositorySrv.saveChanges();                      // Persisto nel db le modifiche
                }
            }

            // Rifaccio tutti i provini in background
            provinare(fotografie);
        }
        protected override void Dispose(bool disposing)
        {
            try {
                // Se il tread di copia è ancora vivo, lo uccido
                if (_threadIdrata != null)
                {
                    if (_threadIdrata.IsAlive)
                    {
                        _threadIdrata.Abort();
                    }
                    else
                    {
                        _threadIdrata.Join();
                    }
                }
            } finally {
            }

            try {
                if (this.fotografie != null)
                {
                    foreach (Fotografia foto in this.fotografie)
                    {
                        AiutanteFoto.disposeImmagini(foto);
                    }
                }
            } finally {
            }

            base.Dispose(disposing);
        }
        void provinatore_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Fotografia foto = (Fotografia)e.UserState;

            bool esistevaRisultante = foto.imgRisultante != null;


            // Rilascio memoria
            AiutanteFoto.disposeImmagini(foto, IdrataTarget.Tutte);

            AiutanteFoto.creaProvinoFoto(foto);

            // Le due foto grandi le rilascio per non intasare la memoria qualora questo metodo è chiamato più volte
            AiutanteFoto.disposeImmagini(foto, IdrataTarget.Originale);
            AiutanteFoto.disposeImmagini(foto, IdrataTarget.Risultante);


            bool esisteRisultante = foto.imgRisultante != null;

            // Siccome è molto probabile che venga idratata l'immagine risultante e siccome sono in un loop,
            // non posso tenere in memoria tanta roba, altrimenti esplode
            if (esisteRisultante && !esistevaRisultante)
            {
                // Significa che l'ho idratata io in questo momento
                AiutanteFoto.disposeImmagini(foto, IdrataTarget.Risultante);
            }


            // Avviso tutti che questa foto è cambiata
            FotoModificateMsg msg = new FotoModificateMsg(this, foto);

            pubblicaMessaggio(msg);
        }
        /// <summary>
        //  azzero la gallery corrente e rilascio la memoria eventualmente utilizzata dalle foto
        /// </summary>
        private void svuotaGalleryCorrente()
        {
            if (fotografie != null)
            {
                foreach (Fotografia f in fotografie)
                {
                    AiutanteFoto.disposeImmagini(f, IdrataTarget.Tutte);
                }

                FormuleMagiche.rilasciaMemoria();
            }
            fotografie = null;
        }
        /// <summary>
        /// Se ho delle foto visibili, rilascio la memoria delle foto più pesanti
        /// poi svuoto la lista
        /// </summary>
        void rilasciaEdAzzeraVisibili()
        {
            if (slidesVisibili != null)
            {
                // Devo rilasciare la memoria delle immagini pesanti precedenti prima di pulire
                foreach (var slideVisibile in slidesVisibili)
                {
                    AiutanteFoto.disposeImmagini(slideVisibile, IdrataTarget.Risultante);
                    AiutanteFoto.disposeImmagini(slideVisibile, IdrataTarget.Originale);
                }

                slidesVisibili.Clear();
            }
        }
        public void DisposeFotografia(Fotografia fotografia)
        {
            if (_fotografiaCorrente == null)
            {
                _fotografiaCorrente = fotografia;
            }

            if (_fotografiaCorrente != null && !_fotografiaCorrente.Equals(fotografia))
            {
                AiutanteFoto.disposeImmagini(_fotografiaCorrente, IdrataTarget.Risultante);
                AiutanteFoto.disposeImmagini(_fotografiaCorrente, IdrataTarget.Originale);
                _fotografiaCorrente = fotografia;
            }
        }
        /// <summary>
        /// Elimino e distruggo le foto sparse indicate
        /// </summary>
        /// <param name="fotosDaCanc"></param>
        public int elimina(IEnumerable <Fotografia> fotosDaCanc)
        {
            _possoChiudere = false;
            int conta = 0;

            _giornale.Info("E' stata richiesta la distruzione di " + fotosDaCanc.Count() + " fotografie. Iniizo eliminazione");

            LumenEntities lumenEntities = UnitOfWorkScope.currentDbContext;

            foreach (Fotografia ff in fotosDaCanc)
            {
                Fotografia ff2 = ff;
                OrmUtil.forseAttacca <Fotografia>(ref ff2);

                AiutanteFoto.disposeImmagini(ff2);

                // Elimino la foto da disco
                seEsisteCancella(PathUtil.nomeCompletoRisultante(ff2));
                seEsisteCancella(PathUtil.nomeCompletoProvino(ff2));
                seEsisteCancella(PathUtil.nomeCompletoOrig(ff2));

                // Poi dal database
                lumenEntities.Fotografie.Remove(ff2);
                _giornale.Debug("Eliminata Fotogarfia dal db: id=" + ff2.id + " num=" + ff2.numero);
                ++conta;
            }


            int test3 = lumenEntities.SaveChanges();


            _giornale.Info("Eliminazione foto completata. Tot = " + conta);
            _giornale.Debug("la SaveChanges ha ritornato: " + test3);

            if (test3 > 0)
            {
                // Rilancio un messaggio in modo che tutta l'applicazione (e tutti i componenti) vengano notificati
                FotoEliminateMsg msg = new FotoEliminateMsg(this as IEliminaFotoVecchieSrv);
                msg.listaFotoEliminate = fotosDaCanc;
                pubblicaMessaggio(msg);
            }

            _possoChiudere = true;
            return(conta);
        }
        public void OnNext(FotoEliminateMsg msg)
        {
            if (slideShow == null)
            {
                return;
            }

            foreach (Fotografia fotoEliminata in msg.listaFotoEliminate)
            {
                // Elimino dalla collezione delle foto quelle che non ci sono più
                int pos = slideShow.slides.IndexOf(fotoEliminata);
                if (pos > 0)
                {
                    AiutanteFoto.disposeImmagini(slideShow.slides [pos], IdrataTarget.Tutte);
                    slideShow.slides.Remove(fotoEliminata);
                }
            }
        }
        /// <summary>
        /// Faccio qualche controllo preventivo.
        /// </summary>
        /// <param name="fotografia"></param>
        /// <param name="ruota"></param>
        public void autoRuotaSuOriginale(Fotografia fotografia, Ruota ruota)
        {
            if (fotografia.correzioniXml != null)
            {
                throw new LumenException("Sulla foto " + fotografia.numero + " esistono correzioni.\nImpossibile ruotare sull'originale.\nRimuovere prima le correzioni (torna originale)");
            }

            if (!ruota.isAngoloRetto)
            {
                throw new ArgumentException("La rotazione sull'originale funziona solo con angoli retti");
            }

            string nomeFileOrig = PathUtil.nomeCompletoOrig(fotografia);
            string estensione   = Path.GetExtension(nomeFileOrig);

            if (fotografia.imgOrig == null)
            {
                AiutanteFoto.idrataImmaginiFoto(fotografia, IdrataTarget.Originale);
            }

            IImmagine imgRuotata = applicaCorrezione(fotografia.imgOrig, ruota);

            string nomeFileBackup = Path.ChangeExtension(nomeFileOrig, "BACKUP" + estensione);

            if (!File.Exists(nomeFileBackup))
            {
                // Salvo per sicurezza il file originale
                File.Move(nomeFileOrig, nomeFileBackup);
            }

            fotografia.imgOrig = imgRuotata;
            gestoreImmaginiSrv.save(imgRuotata, nomeFileOrig);

            AiutanteFoto.creaProvinoFoto(fotografia);

            // Libero memoria. Lascio solo il provino
            AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Originale);
            AiutanteFoto.disposeImmagini(fotografia, IdrataTarget.Risultante);
        }
Exemple #14
0
        public void outOfMemoryImmagini()
        {
            const int quante       = 1000;
            const int ogniTotPurga = 100;

            List <Fotografia> ff = cercaFotoQuasiasi(5);

            // Ricavo la memoria libera prima del test
            long memoryPrima = Process.GetCurrentProcess().WorkingSet64;

            for (int ii = 0; ii < quante; ii++)
            {
                foreach (Fotografia f in ff)
                {
                    AiutanteFoto.idrataImmaginiFoto(f, IdrataTarget.Tutte);

                    AiutanteFoto.disposeImmagini(f, IdrataTarget.Tutte);

                    // ogni tot iterazioni, vado a liberare la memoria che inspiegabilmente non viene pulita.
                    if ((ii % ogniTotPurga) == 0)
                    {
                        // ATTENZIONE: IMPORTANTE.
                        // Se non metto questa formula magica,
                        // il GC non pulisce la memoria occupata dalla bitmap (inspiegabilmente)
                        FormuleMagiche.rilasciaMemoria();
                    }

                    long memoryDurante = Process.GetCurrentProcess().WorkingSet64;
                    long consumata     = (memoryDurante - memoryPrima);

                    // Se supero il massimo impostato, probabilmente il gc non sta pulendo.
                    if (consumata > maxMem)
                    {
                        Assert.Fail("Probabilmente si sta consumando troppa memoria: diff(MB)=" + consumata / 1024);
                    }
                }
            }
        }
        public void clonaImmagineIncorniciata(Fotografia fotoOrig, string nomeFileImg)
        {
            FileInfo fileInfoSrc   = new FileInfo(fotoOrig.nomeFile);
            string   nomeOrig      = fileInfoSrc.Name;
            string   nomeFotoClone = ClonaImmaginiWorker.getNomeFileClone(fotoOrig);
            string   nomeFileDest  = Path.Combine(Config.Configurazione.cartellaRepositoryFoto, Path.GetDirectoryName(fotoOrig.nomeFile), nomeFotoClone);

            //Sposto la foto nella coartellaRepository e gli attribuisco il suo nome originale.
            File.Move(nomeFileImg, nomeFileDest);

            Fotografia fotoMsk = null;

            using (new UnitOfWorkScope(false))
            {
                try
                {
                    fotoMsk    = new Fotografia();
                    fotoMsk.id = Guid.NewGuid();
                    fotoMsk.dataOraAcquisizione = fotoOrig.dataOraAcquisizione;

                    Fotografo f = fotoOrig.fotografo;
                    OrmUtil.forseAttacca <Fotografo>(ref f);
                    fotoMsk.fotografo = f;

                    if (fotoOrig.evento != null)
                    {
                        Evento e = fotoOrig.evento;
                        OrmUtil.forseAttacca <Evento>(ref e);
                        fotoMsk.evento = e;
                    }

                    fotoMsk.didascalia = fotoOrig.didascalia;
                    fotoMsk.numero     = fotoOrig.numero;
                    // Le correzioni non devo duplicarle perché non sono tipiche della composizione finale, ma della foto originale.

                    fotoMsk.faseDelGiorno = fotoOrig.faseDelGiorno;
                    fotoMsk.giornata      = fotoOrig.giornata;

                    // il nome del file, lo memorizzo solamente relativo
                    // scarto la parte iniziale di tutto il path togliendo il nome della cartella di base delle foto.
                    // Questo perché le stesse foto le devono vedere altri computer della rete che
                    // vedono il percorso condiviso in maniera differente.
                    fotoMsk.nomeFile = Path.Combine(Path.GetDirectoryName(fotoOrig.nomeFile), nomeFotoClone);

                    fotografieRepositorySrv.addNew(fotoMsk);
                    fotografieRepositorySrv.saveChanges();
                }

                catch (Exception ee)
                {
                    _giornale.Error("Non riesco ad inserire una foto clonata. Nel db non c'è ma nel filesystem si: " + fotoOrig.nomeFile, ee);
                }

                AiutanteFoto.creaProvinoFoto(nomeFileDest, fotoMsk);

                // Libero la memoria occupata dalle immagini, altrimenti esplode.
                AiutanteFoto.disposeImmagini(fotoMsk, IdrataTarget.Tutte);

                // Notifico la lista delle foto da mandare in modifica
                NuovaFotoMsg msg = new NuovaFotoMsg(this, fotoMsk);
//				msg.descrizione += Configurazione.ID_FOTOGRAFO_ARTISTA;
                LumenApplication.Instance.bus.Publish(msg);
            }
        }
Exemple #16
0
        private void aggiungiImmagineAlCanvas(Canvas canvas, Fotografia foto, double x, double y)
        {
            try {
                // Ricavo l'immagine da stampare
                IImmagine provino;

                if (usoGrande)
                {
                    AiutanteFoto.idrataImmagineDaStampare(foto);
                    provino = AiutanteFoto.idrataImmagineGrande(foto);

                    if (Configurazione.UserConfigLumen.tecSogliaStampaProvini == -3)
                    {
                        IGestoreImmagineSrv g        = LumenApplication.Instance.getServizioAvviato <IGestoreImmagineSrv>();
                        IImmagine           provino2 = g.creaProvino(provino, 1000);
                        provino = (IImmagine)provino2.Clone();
                        ((ImmagineWic)provino).bitmapSource.Freeze();

                        AiutanteFoto.disposeImmagini(foto, IdrataTarget.Originale);
                        AiutanteFoto.disposeImmagini(foto, IdrataTarget.Risultante);
                    }

                    immaginiPaginaPrecedente.Add(provino);
                }
                else
                {
                    AiutanteFoto.idrataImmaginiFoto(foto, IdrataTarget.Provino);
                    provino = foto.imgProvino;
                }



                Image img = new Image();
                img.Stretch          = Stretch.Uniform;
                img.StretchDirection = StretchDirection.Both;

                img.SetValue(Canvas.TopProperty, (Double)(sizeLatoH * (y - 1)) + testataH);
                img.SetValue(Canvas.LeftProperty, (Double)(sizeLatoW * (x - 1) + margin / 2));

                img.Width  = sizeLatoW - margin;
                img.Height = sizeLatoH - margin;

                img.HorizontalAlignment = HorizontalAlignment.Center;
                img.VerticalAlignment   = VerticalAlignment.Center;
                if (provino != null)
                {
                    img.RenderSize = new Size(img.Width, img.Height);                        // TODO tento di tenere bassa la memoria
                    img.BeginInit();
                    BitmapSource bs = ((ImmagineWic)provino).bitmapSource;
                    img.Source = bs;
                    img.EndInit();
                }

                canvas.Children.Add(img);
            } catch (Exception ee) {
                // Non rilancio l'eccezione perché voglio continuare a stampare
                _giornale.Error("Impossibile caricare immagime della foto: " + foto, ee);
            }

            eventualiStampigli(canvas, x, y, foto);
        }
        /**
         * Attenzione:
         * questo metodo deve ritornare l'esito della stampa, quindi non deve essere asincrono.
         * Deve essere sicronizzato
         */
        public EsitoStampa esegui(LavoroDiStampa lavoroDiStampa)
        {
            LavoroDiStampaFoto _lavoroDiStampa = lavoroDiStampa as LavoroDiStampaFoto;

            _giornale.Debug("Sto per avviare il lavoro di stampa: " + lavoroDiStampa.ToString());

            _conta++;

            try {
                string nomeFileFoto = AiutanteFoto.idrataImmagineDaStampare(_lavoroDiStampa.fotografia);

                // Ricavo l'immagine da stampare
                IImmagine immagine = _lavoroDiStampa.fotografia.imgRisultante != null ? _lavoroDiStampa.fotografia.imgRisultante : _lavoroDiStampa.fotografia.imgOrig;

                // Gestisco una eccezione specifica, in questo modo ho un messaggio chiaro di cosa è andato storto.
                if (immagine == null)
                {
                    throw new FileNotFoundException("fotografia = " + _lavoroDiStampa.fotografia, _lavoroDiStampa.fotografia.nomeFile);
                }

                // Devo clonare l'immagine perché negli atri thread potrebbero eseguire delle dispose che me la svuotano
                using (IImmagine immagineDaStampare = (IImmagine)immagine.Clone()) {
                    // TODO BLUCA provo a duplicare l'immagine per evitare l'errore che è di proprietà del thread chiamante.
                    // BitmapSource bmp = new WriteableBitmap( ((ImmagineWic)immagineDaStampare).bitmapSource );
                    // bmp.Freeze();

                    BitmapSource bmp = ((ImmagineWic)immagineDaStampare).bitmapSource;

                    var         match = Regex.Match(lavoroDiStampa.param.nomeStampante, @"(?<machine>\\\\.*?)\\(?<queue>.*)");
                    PrintServer ps1   = null;
                    if (match.Success)
                    {
                        // Come print-server uso il server di rete
                        ps1 = new PrintServer(match.Groups["machine"].Value);
                    }
                    else
                    {
                        // Come print-server uso me stesso
                        ps1 = new PrintServer();
                    }
                    using ( ps1 ) {
                        PrintQueue coda = null;
                        if (match.Success)
                        {
                            coda = ps1.GetPrintQueue(match.Groups["queue"].Value);
                        }
                        else
                        {
                            coda = ps1.GetPrintQueue(lavoroDiStampa.param.nomeStampante);
                        }

                        // Ricavo la coda di stampa (cioè la stampante) e le sue capacità.
                        using ( coda ) {
                            PrintCapabilities capabilities = null;
                            try {
                                capabilities = coda.GetPrintCapabilities();
                            } catch (Exception) {
                                // Le stampanti shinko non supportano
                            }

                            // Imposto la stampante (così che mi carica le impostazioni)
                            PrintDialog dialog = new PrintDialog();
                            dialog.PrintQueue = coda;

                            Size areaStampabile = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);

                            // Imposto qualche attributo della stampa
                            bool piuRealistaDelRe = false;
                            if (piuRealistaDelRe)                                // Meglio non essere più realisti del re.
                            {
                                dialog.PrintTicket.OutputQuality       = OutputQuality.Photographic;
                                dialog.PrintTicket.PhotoPrintingIntent = PhotoPrintingIntent.PhotoBest;
                            }

                            // Compongo il titolo della stampa che comparirà nella descrizione della riga nello spooler di windows
                            StringBuilder titolo = new StringBuilder();
                            titolo.AppendFormat("foto N.{0} Oper={1} gg={2}",
                                                _lavoroDiStampa.fotografia.etichetta,
                                                _lavoroDiStampa.fotografia.fotografo.iniziali,
                                                String.Format("{0:dd-MMM}", _lavoroDiStampa.fotografia.dataOraAcquisizione));
#if DEBUG
                            titolo.Append(" #");
                            titolo.Append(DateTime.Now.ToString("mmssss"));                                  // Uso un numero univoco per evitare doppioni per il doPdf altrimenti mi chiede sempre di sovrascrivere
#endif
                            // Eventuale rotazione dell'orientamento dell'area di stampa
                            // Devo decidere in anticipo se la stampante va girata. Dopo che ho chiamato Print non si può più fare !!!
                            bool _ruotareStampante = false;
                            if (_lavoroDiStampa.param.autoRuota)
                            {
                                if (!ProiettoreArea.isStessoOrientamento(areaStampabile, immagineDaStampare))
                                {
                                    _ruotareStampante = true;
                                }
                            }

                            if (_ruotareStampante)
                            {
                                if (capabilities != null && capabilities.PageOrientationCapability.Contains(PageOrientation.Landscape) && capabilities.PageOrientationCapability.Contains(PageOrientation.Portrait))
                                {
                                    // tutto ok
                                    dialog.PrintTicket.PageOrientation = (dialog.PrintTicket.PageOrientation == PageOrientation.Landscape ? PageOrientation.Portrait : PageOrientation.Landscape);
                                }
                                else
                                {
                                    _giornale.Debug("La stampante " + lavoroDiStampa.param.nomeStampante + " non accetta cambio orientamento landscape/portrait");
                                }

                                // Quando giro la stampante, non mi si girano anche le dimensioni. Ci penso da solo.
                                areaStampabile = ProiettoreArea.ruota(areaStampabile);
                            }

                            //
                            // ----- gestisco il numero di copie
                            //
                            int cicliStampa = 1;
                            if (lavoroDiStampa.param.numCopie > 1)
                            {
                                // Se la stampante gestisce le copie multiple, faccio un invio solo.
                                if (capabilities != null && capabilities.MaxCopyCount >= lavoroDiStampa.param.numCopie)
                                {
                                    dialog.PrintTicket.CopyCount = lavoroDiStampa.param.numCopie;
                                }
                                else
                                {
                                    cicliStampa = lavoroDiStampa.param.numCopie;
                                }
                            }

                            //
                            // ----- Preparo la realizzazione grafica da mandare in output
                            //

                            // Ora creo il documento che andrò a stampare.
                            // L'uso di un FixedDocument, mi permetterà di interagire con misure, dimensioni e margini
                            FixedDocument document = new FixedDocument();
                            document.DocumentPaginator.PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);


                            // Creo una pagina della grandezza massima
                            FixedPage page1 = new FixedPage();
                            page1.Width               = document.DocumentPaginator.PageSize.Width;
                            page1.Height              = document.DocumentPaginator.PageSize.Height;
                            page1.VerticalAlignment   = VerticalAlignment.Center;
                            page1.HorizontalAlignment = HorizontalAlignment.Center;


                            // Per fare in modo che l'immagine venga centrata bene automaticamente, e non venga tagliata solo da una parte ma nel centro,
                            // non devo mettere le dimensioni al componente Image, ma devo creare
                            // una Grid più esterna con le dimensioni precise.
                            Grid grid = new Grid();
                            grid.Height = page1.Height;
                            grid.Width  = page1.Width;


                            // Creo una immagine che contiene la bitmap da stampare
                            Image image = new Image();
                            //						image.BeginInit();
                            image.VerticalAlignment   = VerticalAlignment.Center;
                            image.HorizontalAlignment = HorizontalAlignment.Center;

                            //						BitmapSource clone = bmp.Clone();
                            //						clone.Freeze();
                            image.Source = bmp;

                            if (_lavoroDiStampa.param.autoZoomNoBordiBianchi)
                            {
                                image.Stretch = Stretch.UniformToFill;
                            }
                            else
                            {
                                image.Stretch = Stretch.Uniform;
                            }
                            image.StretchDirection = StretchDirection.Both;

                            //						image.EndInit();

                            grid.Children.Add(image);
                            page1.Children.Add(grid);

                            //
                            eventualiStampigli(page1, _lavoroDiStampa);


                            // add the page to the document
                            PageContent page1Content = new PageContent();
                            page1Content.Child = page1;
                            document.Pages.Add(page1Content);

                            //
                            // ----- STAMPA per davvero
                            //
                            for (int ciclo = 0; ciclo < cicliStampa; ciclo++)
                            {
                                dialog.PrintDocument(document.DocumentPaginator, titolo.ToString());

                                _esito = EsitoStampa.Ok;
                            }
                            _giornale.Debug("Stampa completata");

                            // Per cercare di liberare memoria più possibile svuoto le pagine  forzatamente a mano.
                            // Pare che il GC non riesce a pulire.
                            foreach (var fixedPage in document.Pages.Select(pageContent => pageContent.Child))
                            {
                                fixedPage.Children.Clear();
                            }
                        }         // using printqueue
                    }             // using printserver
                }                 // using iimagine
            } catch (Exception ee) {
                _esito = EsitoStampa.Errore;
                _giornale.Error("Stampa fallita", ee);
            } finally {
                // Rilascio le immagini idratate altrimenti in loop vado in outOfMemory
                AiutanteFoto.disposeImmagini(_lavoroDiStampa.fotografia, IdrataTarget.Risultante);
                AiutanteFoto.disposeImmagini(_lavoroDiStampa.fotografia, IdrataTarget.Originale);

                CoreUtil.abraCadabra();                   //   :-)
            }


            _giornale.Info("Completato lavoro di stampa. Esito = " + _esito + " lavoro = " + lavoroDiStampa.ToString());
            return(_esito);
        }
        /// <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);
        }