/** * Evento che viene rilanciato per stampare tutte le pagine */ void mioPrintPageEventHandler(object sender, PrintPageEventArgs e) { try { // Ricavo l'immagine da stampare IImmagine immagineDaStampare = _lavoroDiStampa.fotografia.imgOrig; // Ricavo tutta l'area stampabile RectangleF areaStampabile = e.PageSettings.PrintableArea; // Non so perchè, ma quando giro la stampante, non mi si girano anche le dimensioni. Ci penso da solo. if (_ruotareStampante) { areaStampabile = ProiettoreArea.ruota(areaStampabile); } // // ----- Calcolo le aree di proiezione // ProiettoreArea proiettore = new ProiettoreArea(areaStampabile); proiettore.autoCentra = true; // Questo lo decido io d'ufficio. Non avrebbe senso altrimenti. proiettore.autoZoomToFit = _lavoroDiStampa.param.autoZoomToFit; proiettore.autoRotate = _lavoroDiStampa.param.autoRuota; Proiezione proiezione = proiettore.calcola(immagineDaStampare); // // ----- Inizio a stampare // // la rotazione non dovrebbe mai avvenire perchè ho già girato la stampante in anticipo Debug.Assert(!proiezione.effettuataRotazione); Graphics grpx = e.Graphics; //set graphics attributes. grpx.SmoothingMode = SmoothingMode.AntiAlias; grpx.InterpolationMode = InterpolationMode.HighQualityBicubic; grpx.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; grpx.PixelOffsetMode = PixelOffsetMode.HighQuality; Image image = ((ImmagineNet)immagineDaStampare).image; grpx.DrawImage(image, proiezione.dest, proiezione.sorg, GraphicsUnit.Pixel); _esito = EsitoStampa.Ok; } catch (Exception ee) { _giornale.Error("Lavoro di stampa fallito: " + _lavoroDiStampa, ee); _esito = EsitoStampa.Errore; } }
/** * 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); }
/** * 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); }