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); }
public static IdrataTarget qualeImmagineDaStampare(Fotografia foto) { // Se ho delle correzioni, allora devo usare il file Risultante. Se non ho modifiche, allora uso l'originale. IdrataTarget quale = (foto.correzioniXml == null ? IdrataTarget.Originale : IdrataTarget.Risultante); return(quale); }
public static void disposeImmagini(Fotografia foto, IdrataTarget quale) { // evito errori if (foto == null) { return; } if (quale == IdrataTarget.Tutte || quale == IdrataTarget.Originale) { if (foto.imgOrig != null) { foto.imgOrig.Dispose(); foto.imgOrig = null; } } if (quale == IdrataTarget.Tutte || quale == IdrataTarget.Provino) { if (foto.imgProvino != null) { foto.imgProvino.Dispose(); foto.imgProvino = null; } } if (quale == IdrataTarget.Tutte || quale == IdrataTarget.Risultante) { if (foto.imgRisultante != null) { foto.imgRisultante.Dispose(); foto.imgRisultante = null; } } }
public void idrataImmaginiFoto(Fotografia foto, IdrataTarget target, bool forzatamente) { String nomeCompleto = null; try { // if (forzatamente || foto.imgProvino == null) { if ((target & IdrataTarget.Provino) != 0) { nomeCompleto = PathUtil.nomeCompletoProvino(foto); foto.imgProvino = this.load(nomeCompleto); } } // if (forzatamente || foto.imgOrig == null) { if ((target & IdrataTarget.Originale) != 0) { nomeCompleto = PathUtil.nomeCompletoFoto(foto); foto.imgOrig = this.load(nomeCompleto); } } // if (forzatamente || foto.imgRisultante == null) { if ((target & IdrataTarget.Risultante) != 0) { nomeCompleto = PathUtil.nomeCompletoRisultante(foto); // Se mi chiedono idratare tutte le foto, e quella modificata non esiste, non do errore. if (target == IdrataTarget.Tutte && !File.Exists(nomeCompleto)) { // E' possibile che la foto modificata non esista. Mentre le altre devono esistere (provino e originale) } else { foto.imgRisultante = this.load(nomeCompleto); } } } } catch (Exception ee) { // Se non riesco a caricare una immagine, non posso farci niente qui. Devo tirare dritto. _giornale.Warn(ee.Message + " nomeCompleto=" + nomeCompleto, ee); Messaggio msg = new Messaggio(ee.Source); msg.esito = Esito.Errore; msg.descrizione = ee.Message; msg.showInStatusBar = true; pubblicaMessaggio(msg); throw ee; } }
public static string idrataImmaginiFoto(Fotografia foto, IdrataTarget target, bool forzatamente) { System.Diagnostics.Debug.Assert(foto != null); // Non deve succedere. Punto e basta. IGestoreImmagineSrv gis = LumenApplication.Instance.getServizioAvviato <IGestoreImmagineSrv>(); gis.idrataImmaginiFoto(foto, target, forzatamente); return(PathUtil.nomeCompletoFile(foto, target)); }
public static string nomeCompletoFile(Fotografia foto, IdrataTarget quale) { if (quale == IdrataTarget.Originale) { return(nomeCompletoFoto(foto)); } if (quale == IdrataTarget.Provino) { return(nomeCompletoProvino(foto)); } if (quale == IdrataTarget.Risultante) { return(nomeCompletoRisultante(foto)); } throw new ArgumentException(quale.ToString()); }
/// <summary> /// Devo stampare la foto. /// Quindi mi serve indietro una immagine grande, che può essere l'originale, oppure quella modificata. /// L'immagine modificata, però potrebbe ancora non essere stata calcolata. In tal caso ci penso io. /// /// </summary> /// <param name="foto"></param> /// <returns>il nome del file interessato su disco</returns> public static string idrataImmagineDaStampare(Fotografia foto) { IdrataTarget quale = qualeImmagineDaStampare(foto); // Ho delle correzioni che non sono ancora state applicate. Lo faccio adesso. if (foto.imgRisultante == null && foto.correzioniXml != null) { // Se il file esiste già su disco, allora uso quello. if (!File.Exists(PathUtil.nomeCompletoRisultante(foto))) { creaRisultanteFoto(foto); } } var nome = AiutanteFoto.idrataImmaginiFoto(foto, quale, true); return(nome); }
/// <summary> /// Quando lavoro con una singola foto, se vado sullo schermo del pubblico, /// devo fare vedere la foto più bella che ho (cioè quella grande) /// Il problema è che la foto grande, potrebbe ancora non essere stata calcolata /// </summary> /// <param name="fotografia"></param> /// public void eseguiSnapshotSuFinestraPubblica(Fotografia fotografia, bool forzaAperturaWin) { // Se la finestra è chiusa e il flag non mi forza l'apertura non faccio niente if (!forzaAperturaWin && _snapshotPubblicoWindow == null) { return; } FotoDisposeUtils.Instance().DisposeFotografia(fotografia); IdrataTarget quale = AiutanteFoto.qualeImmagineDaStampare(fotografia); AiutanteFoto.idrataImmagineDaStampare(fotografia); IImmagine immagine = AiutanteFoto.getImmagineFoto(fotografia, quale); forseApriSnapshotPubblicoWindow(); snapshotPubblicoViewModel.snapshotImageSource = ((ImmagineWic)immagine).bitmapSource; }
public static IImmagine getImmagineFoto(Fotografia f, IdrataTarget quale) { IImmagine immagine = null; switch (quale) { case IdrataTarget.Originale: immagine = f.imgOrig; break; case IdrataTarget.Risultante: immagine = f.imgRisultante; break; case IdrataTarget.Provino: immagine = f.imgProvino; break; } return(immagine); }
private void viewFotoFullScreen() { // Qui devo capire quale foto verrà idratata IdrataTarget quale = AiutanteFoto.qualeImmagineDaStampare(singolaFotoTarget); // Qui idrato AiutanteFoto.idrataImmagineDaStampare(singolaFotoTarget); // Qui ricavo la foto IImmagine img = AiutanteFoto.getImmagineFoto(singolaFotoTarget, quale); var imageSource = ((ImmagineWic)img).bitmapSource as ImageSource; // Qui passo la foto al viewmodel che la deve visualizzare PanAndZoomViewModel panZommViewModel = new PanAndZoomViewModel(imageSource); // TODO anti-pattern : aprire finestre nel WiewModel. // usare openPopupDialogRequest come già fatto per associazione faccia fotografo PanAndZoomWindow w = new Digiphoto.Lumen.UI.PanAndZoom.PanAndZoomWindow(); w.DataContext = panZommViewModel; w.ShowDialog(); }
/// <summary> /// Devo gestire le correzioni complicate /// </summary> /// <param name="immaginePartenza"></param> /// <param name="correzioni"></param> /// <returns></returns> private IImmagine rigeneraImmagineConCorrezioniComplicate(IImmagine immaginePartenza, CorrezioniList correzioni, IdrataTarget qualeTarget) { double wwDest = 0, hhDest = 0; BitmapSource bmpFoto = null; // Questa è la foto BitmapSource bmpMaschera = null; // Questa è la maschera (eventuale) bmpFoto = ((ImmagineWic)immaginePartenza).bitmapSource; // ::: Per prima cosa calcolo la dimensione che deve avere l'immagine di uscita (il canvas) // Verifico quindi se c'è una maschera. In tal caso comanda lei Imaging.Correzioni.Mascheratura mascheratura = (Imaging.Correzioni.Mascheratura)correzioni.FirstOrDefault(c => c is Imaging.Correzioni.Mascheratura); // La mascheratura potrebbe essere anche indicata come orientabile if (mascheratura == null) { Imaging.Correzioni.MascheraturaOrientabile mascheraturaOrientabile = (Imaging.Correzioni.MascheraturaOrientabile)correzioni.FirstOrDefault(c => c is Imaging.Correzioni.MascheraturaOrientabile); if (mascheraturaOrientabile != null) { // Ora estraggo la mascheratura giusta per questa foto if (immaginePartenza.orientamento == Orientamento.Verticale) { mascheratura = mascheraturaOrientabile.mascheraturaV; } if (immaginePartenza.orientamento == Orientamento.Orizzontale) { mascheratura = mascheraturaOrientabile.mascheraturaH; } } } // // Ora che ho scoperto se esiste una mascheratura, la applico // if (mascheratura != null) { ImmagineWic immagineMaschera = new ImmagineWic(Path.Combine(getCartellaMaschera(FiltroMask.MskSingole), mascheratura.nome)); bmpMaschera = immagineMaschera.bitmapSource; // Carico la maschera per avere le dimensioni reali definitive if (qualeTarget == IdrataTarget.Provino) { IImmagine imgMascheraPiccola = gestoreImmaginiSrv.creaProvino(immagineMaschera); bmpMaschera = ((ImmagineWic)imgMascheraPiccola).bitmapSource; } wwDest = bmpMaschera.PixelWidth; hhDest = bmpMaschera.PixelHeight; } else { // Cerco di intercettare un eventuale rotazione del quadro (non della foto) Zoom zzz = (Zoom)correzioni.FirstOrDefault(c => c is Zoom); bool rovesciare = zzz != null ? zzz.quadroRuotato : false; if (rovesciare) { wwDest = bmpFoto.PixelHeight; hhDest = bmpFoto.PixelWidth; } else { wwDest = bmpFoto.PixelWidth; hhDest = bmpFoto.PixelHeight; } } // ::: Il canvas Canvas canvas = new Canvas(); canvas.Background = new SolidColorBrush(Colors.White); canvas.Width = wwDest; canvas.Height = hhDest; canvas.HorizontalAlignment = HorizontalAlignment.Left; canvas.VerticalAlignment = VerticalAlignment.Top; #region Correzioni // ::: Gestisco le correzioni TransformGroup traGroup = new TransformGroup(); IList <ShaderEffect> effetti = null; // bool quadroRuotato = false; foreach (Correzione correzione in correzioni) { Correttore correttore = gestoreImmaginiSrv.getCorrettore(correzione); if (correttore.CanConvertTo(typeof(Transform))) { // ::: Trasformazioni Transform trasformazione = (Transform)correttore.ConvertTo(correzione, typeof(Transform)); // La trasformazione di spostamento, (Trasla) fa una eccezione perché dipende dalla grandezza del target. // Devo sistemarla al volo if (trasformazione is TranslateTransform) { TranslateTransform tt = (TranslateTransform)trasformazione; // TODO riproporzionare TranslateTransform tt2 = new TranslateTransform(); // Devo riproporzionare X e Y alla dimensione giusta finale. // posx:300=x:finalW -> x = posx * finalW / 300 tt2.X = ((TranslateTransform)tt).X * canvas.Width / ((Trasla)correzione).rifW; tt2.Y = ((TranslateTransform)tt).Y * canvas.Height / ((Trasla)correzione).rifH; traGroup.Children.Add(tt2); } else { traGroup.Children.Add(trasformazione); } } else if (correttore.CanConvertTo(typeof(ShaderEffectBase))) { // ::: Effetti li sommo poi li faccio tutti in una volta per essere più veloce if (effetti == null) { effetti = new List <ShaderEffect>(); } effetti.Add((ShaderEffect)correttore.ConvertTo(correzione, typeof(ShaderEffectBase))); } } #endregion Correzioni if (effetti != null && effetti.Count > 0) { bmpFoto = EffectsUtil.RenderImageWithEffectsToBitmap(bmpFoto, effetti); } // ::: La foto Image fotona = new Image(); fotona.BeginInit(); fotona.Source = bmpFoto; // bmpFoto; fotona.Stretch = Stretch.Uniform; fotona.HorizontalAlignment = HorizontalAlignment.Center; fotona.VerticalAlignment = VerticalAlignment.Center; fotona.Width = wwDest; fotona.Height = hhDest; fotona.EndInit(); // Assegno tutte le trasformazioni if (traGroup != null && traGroup.Children.Count > 0) { fotona.RenderTransform = traGroup; fotona.RenderTransformOrigin = new Point(0.5, 0.5); // centrate } canvas.Children.Add(fotona); // ::: La Maschera - per concludere, aggiungo anche la maschera che deve ricoprire tutto. Image imageMaschera; if (bmpMaschera != null) { imageMaschera = new Image(); imageMaschera.BeginInit(); imageMaschera.Stretch = Stretch.Uniform; imageMaschera.HorizontalAlignment = HorizontalAlignment.Left; imageMaschera.VerticalAlignment = VerticalAlignment.Top; imageMaschera.Source = bmpMaschera; imageMaschera.Width = wwDest; imageMaschera.Height = hhDest; imageMaschera.EndInit(); canvas.Children.Add(imageMaschera); } // Devo "Arrangiare" il canvas altrimenti non ha dimensione (e la foto viene nera) var size = new Size(wwDest, hhDest); canvas.Measure(size); canvas.Arrange(new Rect(size)); IImmagine immagineMod = null; // Creo la bitmap di ritorno RenderTargetBitmap rtb = new RenderTargetBitmap((int)canvas.Width, (int)canvas.Height, 96d, 96d, PixelFormats.Pbgra32); rtb.Render(canvas); if (rtb.CanFreeze) { rtb.Freeze(); } immagineMod = new ImmagineWic(rtb); // Come penultima cosa, mi rimane da gestire le Scritte (in realtà una sola) foreach (var scritta in correzioni.OfType <Scritta>()) { Correttore correttore = gestoreImmaginiSrv.getCorrettore(scritta); immagineMod = correttore.applica(immagineMod, scritta); } // Per ultima cosa, mi rimane fuori un evenuale logo ... Logo correzioneLogo = (Logo)correzioni.FirstOrDefault(c => c is Logo); if (correzioneLogo != null) { Correttore correttore = gestoreImmaginiSrv.getCorrettore(correzioneLogo); immagineMod = correttore.applica(immagineMod, correzioneLogo); } // Questa forzatura anche se filosoficamente non è bella, ma mi serve per essere più veloce a creare le correzioni complesse sulla foto da stampare. // .. oppure una eventuale area di rispetto (solo sul provino) if (qualeTarget == IdrataTarget.Provino) { AreaRispetto correzioneAreaRispetto = (AreaRispetto)correzioni.FirstOrDefault(c => c is AreaRispetto); if (correzioneAreaRispetto != null) { Correttore correttore = gestoreImmaginiSrv.getCorrettore(correzioneAreaRispetto); immagineMod = correttore.applica(immagineMod, correzioneAreaRispetto); } } return(immagineMod); }
/// <summary> /// Prendo la foto pulita e applico tutte le correzioni. /// Serve per il fotoritocco. /// Faccio tutto in un unico colpo per essere più efficiente. /// </summary> /// <param name="fotografia"></param> /// <param name="cosaRicalcolo"></param> public IImmagine applicaCorrezioni(IImmagine partenza, CorrezioniList correzioni, IdrataTarget cosaRicalcolo) { IImmagine modificata = partenza; // Ci sono alcune correzioni che sono più "complicate" e non posso trattarle in modo singolo, // ma devo gestire nell'insieme in modo efficiente. // In questo caso devo cambiare strategia. bool complicato = false; if (correzioni.SingleOrDefault(c => c is Imaging.Correzioni.Mascheratura) != null || correzioni.SingleOrDefault(c => c is Imaging.Correzioni.MascheraturaOrientabile) != null || correzioni.SingleOrDefault(c => c is Ruota && ((Ruota)c).isAngoloRetto == false) != null || correzioni.SingleOrDefault(c => c is Trasla) != null || correzioni.SingleOrDefault(c => c is Zoom) != null) { complicato = true; } if (complicato) { modificata = rigeneraImmagineConCorrezioniComplicate(partenza, correzioni, cosaRicalcolo); } else { // le correzioni sono tutte applicabili singolarmente. Non necessito di ricalcolo foreach (Correzione correzione in correzioni) { modificata = applicaCorrezione(modificata, correzione); } } return(modificata); }
/** * Devo caricare gli attributi transienti della fotografia */ public static string idrataImmaginiFoto(Fotografia foto, IdrataTarget target) { return(idrataImmaginiFoto(foto, target, false)); }
/// <summary> /// Creo il Provino, e/o la Risultante di una foto e scrivo l'immagine su disco nel file indicato /// </summary> /// <param name="nomeFileSorgente">E' il nome del file della foto vera, grande</param> /// <param name="foto"></param> private static void creaCacheFotoSuDisco(Fotografia foto, IdrataTarget quale, string nomeFileOriginale) { _giornale.Debug("Creo provino foto n." + foto.numero + " target=" + quale); Debug.Assert(quale == IdrataTarget.Provino || quale == IdrataTarget.Risultante); IGestoreImmagineSrv gis = LumenApplication.Instance.getServizioAvviato <IGestoreImmagineSrv>(); IFotoRitoccoSrv fr = LumenApplication.Instance.getServizioAvviato <IFotoRitoccoSrv>(); // Carico l'immagine grande originale (solo la prima volta) bool caricataOrig = false; if (foto.imgOrig == null) { _giornale.Debug("carico immagine originale da disco: " + nomeFileOriginale); foto.imgOrig = gis.load(nomeFileOriginale); caricataOrig = true; } // carico eventuali correzioni CorrezioniList correzioni = null; if (foto.correzioniXml != null) { try { correzioni = SerializzaUtil.stringToObject <CorrezioniList>(foto.correzioniXml); } catch (Exception ee) { // Se ci fossero inciampi con le correzioni, preferisco perderle che far saltare tutto. // Non dovrebbe mai capitare. _giornale.Error("Deserializza correzioni foto = " + foto.id, ee); } } // Se devo crere il provino ma la foto contiene la correzione di Zoom, // devo passare dalla foto grande, altrimenti perde di qualità bool devoPassareDallaGrande = false; if (quale == IdrataTarget.Risultante) { devoPassareDallaGrande = true; } if (correzioni != null && correzioni.Contains(typeof(Zoom))) { devoPassareDallaGrande = true; } // Se richiesto nella configurazione, scrivo direttamente sul provino le righe tratteggiate di rispetto area stampabile bool aggiungiCorrezioneAreaRispetto = false; if (Configurazione.UserConfigLumen.imprimereAreaDiRispetto) { if (quale == IdrataTarget.Provino) { if (correzioni == null) { correzioni = new CorrezioniList(); } if (!correzioni.Contains(typeof(AreaRispetto))) { aggiungiCorrezioneAreaRispetto = true; } } } // Cancello il file Risultante da disco perchè tanto sta per cambiare. IImmagine immagineDestinazione = null; foto.imgRisultante = null; string nomeFileRisultante = PathUtil.nomeCompletoFile(foto, IdrataTarget.Risultante); if (File.Exists(nomeFileRisultante)) { File.Delete(nomeFileRisultante); } // Eventuale creazione delle cartelle di destinazione (potrebbero non esistere) PathUtil.creaCartellaProvini(foto); PathUtil.creaCartellaRisultanti(foto); // OK partiamo! if (devoPassareDallaGrande) { immagineDestinazione = (IImmagine)foto.imgOrig.Clone(); // creo un duplicato della Originale per poi lavorarci } else { immagineDestinazione = gis.creaProvino(foto.imgOrig); // creo una immagine più piccola } // applico eventuali correzioni if (correzioni != null) { IdrataTarget tempQuale = quale; if (devoPassareDallaGrande && quale == IdrataTarget.Provino) { tempQuale = IdrataTarget.Risultante; } if (aggiungiCorrezioneAreaRispetto && tempQuale == IdrataTarget.Provino) { correzioni.Add(areaRispetto); } immagineDestinazione = fr.applicaCorrezioni(immagineDestinazione, correzioni, tempQuale); // NO : non funziona sempre bene. // Se sto facendo un provino che prevede lo zoom, devo passare dalla immagine grande, // quindi sono obbligato a ricalcolare la Risultante e quindi rimpicciolirla. // quindi per essere efficiente, salvo la Risultante che ho già pronta (cosi risparmio tempo dopo) if (devoPassareDallaGrande && quale == IdrataTarget.Provino) { gis.save(immagineDestinazione, nomeFileRisultante); foto.imgRisultante = immagineDestinazione; // Poi la ritaglio per fare il provino buono. immagineDestinazione = gis.creaProvino(immagineDestinazione); // Aggiungo l'area di rispetto al provino if (aggiungiCorrezioneAreaRispetto) { immagineDestinazione = fr.applicaCorrezione(immagineDestinazione, areaRispetto); } } } // Salvo su disco l'immagine di destinazione string nomeFileDest = PathUtil.nomeCompletoFile(foto, quale); gis.save(immagineDestinazione, nomeFileDest); _giornale.Debug("Ho ricreato il file immagine di cache: " + nomeFileDest); // Eventualmente chiudo l'immagine grande se l'avevo aperta io. // Il provino, invece lo lascio aperto (non so se mi causerà problemi di memoria) if (caricataOrig) { AiutanteFoto.disposeImmagini(foto, IdrataTarget.Originale); } // Modifico la foto che mi è stata passata. if (quale == IdrataTarget.Provino) { foto.imgProvino = immagineDestinazione; } if (quale == IdrataTarget.Risultante) { foto.imgRisultante = immagineDestinazione; } }
private static void creaCacheFotoSuDisco(Fotografia foto, IdrataTarget quale) { creaCacheFotoSuDisco(foto, quale, PathUtil.nomeCompletoFoto(foto)); }