public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { double ret = Double.NaN; WpfScreen scr = values[0] as WpfScreen; // Grandezza della griglia dove visualizzo lo schermino blu virtuale // Se il parametro è minuscolo, allora devo gestire if (values.Length > 1) { GestoreFinestrePubbliche gfp = values[1] as GestoreFinestrePubbliche; WpfScreen scrSS = gfp.getScreenSlideShow(); // Se lo schermo dove è presente lo ss non è quello che sto elaborando, allora esco if (scrSS == null || scrSS.deviceEnum != scr.deviceEnum) { return((double)0); } Int32Rect dest = new Int32Rect(0, 0, 200, 200); ProiettoreArea p = new ProiettoreArea(dest); Int32Rect source = new Int32Rect((int)scrSS.WorkingArea.Left, (int)scrSS.WorkingArea.Top, (int)scrSS.WorkingArea.Width, (int)scrSS.WorkingArea.Height); p.autoCentra = true; Proiezione proiezione = p.calcola(source); // Ora uso l'area risultante, come destinazione per la dimensione dello SS ProiettoreArea p2 = new ProiettoreArea(proiezione.dest); Int32Rect ssSorg = new Int32Rect(gfp.geomSS.Left, gfp.geomSS.Top, gfp.geomSS.Width, gfp.geomSS.Height); Proiezione proiezione2 = p2.calcola(ssSorg); if ("l".Equals(parameter)) { ret = proiezione2.dest.X; } if ("T".Equals(parameter)) { ret = proiezione2.dest.Y; } if ("W".Equals(parameter)) { ret = proiezione2.dest.Width; } if ("H".Equals(parameter)) { ret = proiezione2.dest.Height; } } else { Int32Rect dest = new Int32Rect(0, 0, 200, 200); ProiettoreArea p = new ProiettoreArea(dest); Int32Rect source = new Int32Rect((int)scr.WorkingArea.Left, (int)scr.WorkingArea.Top, (int)scr.WorkingArea.Width, (int)scr.WorkingArea.Height); p.autoCentra = true; Proiezione proiezione = p.calcola(source); if ("L".Equals(parameter)) { ret = proiezione.dest.X; } if ("T".Equals(parameter)) { ret = proiezione.dest.Y; } if ("W".Equals(parameter)) { ret = proiezione.dest.Width; } if ("H".Equals(parameter)) { ret = proiezione.dest.Height; } } return(ret); }
/** * Attenzione: * questo metodo deve ritornare l'esito della stampa, quindi non deve essere asincrono. * Deve essere sicronizzato */ public EsitoStampa esegui(LavoroDiStampa lavoroDiStampa) { LavoroDiStampaTessera _lavoroDiStampa = lavoroDiStampa as LavoroDiStampaTessera; _giornale.Debug("Sto per avviare il lavoro di stampa: " + lavoroDiStampa.ToString()); _conta++; try { 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 stmpanti 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 = true; 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 String titolo = "Foto Tessera"; // 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 (_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.Warn("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; } } // Ora creo il documento che andrò a stampare. using (TesseraDocPaginator documentPaginator = new TesseraDocPaginator(_lavoroDiStampa, areaStampabile)) { // // ----- STAMPA per davvero // for (int ciclo = 0; ciclo < cicliStampa; ciclo++) { dialog.PrintDocument(documentPaginator, titolo); _esito = EsitoStampa.Ok; } _giornale.Debug("Stampa tessera completata"); } } } } catch (Exception ee) { _esito = EsitoStampa.Errore; _giornale.Error("Stampa tessera fallita", ee); } _giornale.Info("Completato lavoro di stampa. Esito = " + _esito + " lavoro = " + lavoroDiStampa.ToString()); return(_esito); }
/** * 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); }
private double calcolaDimensione(string qualeFascia, string qualeDimens, object[] values) { // Ricavo dal vettore dei parametri delle variabili con un nome più chiaro. float ratioCarta = (float)values[0]; if (ratioCarta == 0) // probabilmente non è indicata nemmeno una stampante { return(0d); } double imageW = (double)values [1]; double imageH = (double)values [2]; double imageActualW = (double)values [3]; double imageActualH = (double)values [4]; if (imageW == 0d || imageH == 0d) { return(0d); } if (imageActualW == 0d || imageActualH == 0d) { return(0d); } // ----- float ratioImage = (float)(imageActualW / imageActualH); // I due rapporti mi indicano che sia la foto che l'area stampabile siano nella stesso verso (Orizzontali o Verticali entrambi) if (ratioImage < 1 && ratioCarta >= 1 || ratioImage >= 1 && ratioCarta < 1) { // non sono dello stesso verso. lo giro! ratioCarta = (1f / ratioCarta); } // Se la carta è più grande della foto (inteso come rapporto), allora devo tagliare sopra. // Questo mi garantisce il corretto funzionamento indipendentemente dal verso della foto. // Quindi le due bande colorate saranno sopra e sotto in orizzontale // Nel caso contrario saranno a sinistra e destra in verticale. bool eseguoTaglioOrizz = (ratioCarta > ratioImage); // ----- // Ora creo due rettangoli per poter usare il ProiettoreArea Int32Rect fotoSorgente = new Int32Rect(0, 0, (int)imageActualW, (int)imageActualH); // creo un area dello stesso orientamento int cartaW = (int)(1000 * ratioCarta); int cartaH = (int)(cartaW / ratioCarta); Int32Rect stampanteFinta = new Int32Rect(0, 0, cartaW, cartaH); // Eseguo proiezione per capire dove e quanto verrà tagliata la foto originale. ProiettoreArea proiettore = new ProiettoreArea(stampanteFinta, true); Proiezione proiezione = proiettore.calcola(fotoSorgente); // ----- // // Ora finalmente calcolo il valore da ritornare // // ----- double ret = 0d; // Width if (qualeDimens == "W") { if (eseguoTaglioOrizz) { ret = (double)proiezione.sorg.Width; } else { ret = (double)proiezione.sorg.X; } } // Height if (qualeDimens == "H") { if (eseguoTaglioOrizz) { ret = (double)proiezione.sorg.Y; } else { ret = (double)proiezione.sorg.Height; } } // Left (del canvas) if (qualeDimens == "L") { double offsetX = (imageW - imageActualW) / 2; if (qualeFascia == "b" && eseguoTaglioOrizz == false) { offsetX += (imageActualW - proiezione.sorg.X); } ret = offsetX; } // Top (del canvas) if (qualeDimens == "T") { double offsetY = (imageH - imageActualH) / 2; if (qualeFascia == "b" && eseguoTaglioOrizz == true) { offsetY += (imageActualH - proiezione.sorg.Y); } ret = offsetY; } return(ret); }