Categories
.NET Desarrollo de Software Miniposts WordPress

Enlaces varios

Algunos enlaces que posiblemente les interesen:

Categories
.NET Miniposts

Visual Studio 2008 (Orcas) – Beta 2

S. Somasegar anuncia que ya está disponible para descarga la beta 2 de Visual Studio 2008 (a.k.a Visual Studio Orcas):

Imágenes para Virtual PC

Categories
.NET Utilidades

Reflexil, modifica ensamblados .NET desde Reflector

En un comentario del artículo donde mencionaba algunas características de Cecil, me hacían conocer la existencia de NetDasm, que es una herramienta para modificar ensamblados .NET. Semanas después, supe de la existencia de Reflexil, que a diferencia del anterior, éste es un plugin para Reflector

Reflexil, modifica ensamblados .NET desde Reflector

En la última versión, este plugin permite modificar el código tanto en IL como C#. Pueden descargar los binarios o el código fuente.

Categories
.NET

Problemas de codificación en .NET

Hace poco, me acabo de topar con un bug bastante particular en una aplicación desarrollada en .NET. El problema radica en que el .NET Framework -- al parecer -- usa diferentes codificaciones para realizar ciertas conversiones en algunos métodos/propiedades de ciertas clases (Ej. Assembly, Uri).

Pude aislar el problema a lo siguiente:

csharp:

using System;
using System.Reflection;

class Program
{
    static void Main(string[] args)
    {
        string rutaEnsamblado = @"I:\tests\Administración\itextsharp.dll";

        Assembly ensamblado = Assembly.LoadFrom(rutaEnsamblado);

        Uri uri = new Uri(ensamblado.EscapedCodeBase);
       
        Console.WriteLine(ensamblado.EscapedCodeBase);
        Console.WriteLine(uri.LocalPath);

        uri = new Uri(@"file:///I:\tests\Administraci%c3%b3n\itextsharp.dll");
        Console.WriteLine("\nEn UTF-8: {0}", uri.LocalPath);
    }
}

Salida del programa:

[code num=1 start=1]file:///I:/tests/Administraci%F3n/itextsharp.dll
I:\tests\Administraci?n\itextsharp.dll

En UTF-8: I:\tests\Administración\itextsharp.dll[/code]

Salida de Encoding.Default:

code:

{System.Text.SBCSCodePageEncoding}
    [System.Text.SBCSCodePageEncoding]: {System.Text.SBCSCodePageEncoding}
    BodyName: "iso-8859-1"
    CodePage: 1252
    DecoderFallback: {System.Text.InternalDecoderBestFitFallback}
    EncoderFallback: {System.Text.InternalEncoderBestFitFallback}
    EncodingName: "Western European (Windows)"
    HeaderName: "Windows-1252"
    IsBrowserDisplay: true
    IsBrowserSave: true
    IsMailNewsDisplay: true
    IsMailNewsSave: true
    IsReadOnly: true
    IsSingleByte: true
    WebName: "Windows-1252"
    WindowsCodePage: 1252

En la línea 1 de la salida del programa, se puede ver que el caracter ó inicialmente es convertido en %F3 al invocar a EscapedCodeBase, pero en la propiedad LocalPath de la clase Uri, en mi opinión, intenta decodificarse este valor asumiendo que el mismo está en UTF-8, la prueba de esta afirmación es la línea 4.

Actualmente, sólo existe una solución parcial -- y fea -- a este problema, que es codificar manualmente ciertos caracteres. Si alguien tiene una alternativa mejor o sabe como establecer la codificación por omisión de una aplicación sin tener que tocar la configuración del sistema operativo, estaré muy agradecido. 🙂

Categories
.NET ASP.NET Software Libre Windows Forms

Unir documentos PDF con .NET

Actualización (19/07/2007): Luis Ruiz Pavón comenta una forma más sencilla de unir documentos usando iTextDotNet.

Una pequeña clase que hace uso de iText# (Software Libre) para unir dos o más documentos PDF en uno solo.

csharp:

using System;
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

public class PdfMerge
{
    private BaseFont baseFont;
    private bool enablePagination = false;
    private readonly List<PdfReader> documents;
    private int totalPages;

    public BaseFont BaseFont
    {
        get { return baseFont; }
        set { baseFont = value; }
    }

    public bool EnablePagination
    {
        get { return enablePagination; }
        set
        {
            enablePagination = value;
            if (value && baseFont == null)
                baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
        }
    }

    public List<PdfReader> Documents
    {
        get { return documents; }
    }

    public void AddDocument(string filename)
    {
        documents.Add(new PdfReader(filename));
    }
    public void AddDocument(Stream pdfStream)
    {
        documents.Add(new PdfReader(pdfStream));
    }
    public void AddDocument(byte[] pdfContents)
    {
        documents.Add(new PdfReader(pdfContents));
    }
    public void AddDocument(PdfReader pdfDocument)
    {
        documents.Add(pdfDocument);
    }

    public void Merge(string outputFilename)
    {
        Merge(new FileStream(outputFilename, FileMode.Create));
    }
    public void Merge(Stream outputStream)
    {
        if (outputStream == null || !outputStream.CanWrite)
            throw new Exception("OutputStream es nulo o no se puede escribir en éste.");

        Document newDocument = null;
        try
        {
            newDocument = new Document();
            PdfWriter pdfWriter = PdfWriter.GetInstance(newDocument, outputStream);

            newDocument.Open();
            PdfContentByte pdfContentByte = pdfWriter.DirectContent;

            if (EnablePagination)
                documents.ForEach(delegate(PdfReader doc)
                                  {
                                      totalPages += doc.NumberOfPages;
                                  });

            int currentPage = 1;
            foreach (PdfReader pdfReader in documents)
            {
                for (int page = 1; page <= pdfReader.NumberOfPages; page++)
                {
                    newDocument.NewPage();
                    PdfImportedPage importedPage = pdfWriter.GetImportedPage(pdfReader, page);
                    pdfContentByte.AddTemplate(importedPage, 0, 0);

                    if (EnablePagination)
                    {
                        pdfContentByte.BeginText();
                        pdfContentByte.SetFontAndSize(baseFont, 9);
                        pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
                            string.Format("{0} de {1}", currentPage++, totalPages), 520, 5, 0);
                        pdfContentByte.EndText();
                    }
                }
            }
        }
        finally
        {
            outputStream.Flush();
            if (newDocument != null)
                newDocument.Close();
            outputStream.Close();
        }
    }

    public PdfMerge()
    {
        documents = new List<PdfReader>();
    }
}

Si bien es cierto que hay muchas cosas por mejorar, creo que para escenarios no muy complejos basta y sobra.

Pueden descargar la solución creada en Visual Studio 2005 que -- incluye el ensamblado iText# y -- como ejemplo une dos papers bastante interesantes ("Composable Memory Transactions" y "Static Typing Where Posible, Dynamic Typing When Needed: The End of The Cold War Between Programming Languages").

Nota: La clase está basada en el artículo Merge PDF files with iText.