Alterar a orientação de impressão de um documento de processamento de texto
Este tópico mostra como utilizar as classes no SDK Open XML para o Office para definir programaticamente a orientação de impressão de um documento do Microsoft Word. Contém um método de exemplo SetPrintOrientation
para ilustrar esta tarefa.
SetPrintOrientation Method
Pode utilizar o SetPrintOrientation
método para alterar a orientação de impressão de um documento de processamento de palavras. O método aceita dois parâmetros que indicam o nome do documento a modificar (cadeia) e a nova orientação de impressão (PageOrientationValues).
O código seguinte mostra o SetPrintOrientation
método .
static void SetPrintOrientation(string fileName, string orientation)
Para cada secção no documento, se a nova orientação for diferente da orientação de impressão atual da secção, o código modifica a orientação de impressão da secção. Além disso, o código tem de atualizar manualmente a largura, a altura e as margens de cada secção.
Chamar o Método SetPrintOrientation de Exemplo
Para chamar o método de exemplo SetPrintOrientation
, transmita uma cadeia que contenha o nome do ficheiro a converter e a cadeia "horizontal" ou "vertical", consoante a orientação pretendida. O código seguinte mostra uma chamada de método de exemplo.
SetPrintOrientation(args[0], args[1]);
Como Funciona o Código
Primeiro, o código seguinte determina a orientação a aplicar e, em seguida, abre o documento com o Open método e define o isEditable
parâmetro como para true
indicar que o documento deve ser de leitura/escrita. O código obtém uma referência à parte do documento main e, em seguida, utiliza essa referência para obter uma coleção de todos os descendentes do tipo SectionProperties no conteúdo do documento. O código posterior utilizará esta coleção para definir a orientação de cada secção.
PageOrientationValues newOrientation = orientation.ToLower() switch
{
"landscape" => PageOrientationValues.Landscape,
"portrait" => PageOrientationValues.Portrait,
_ => throw new System.ArgumentException("Invalid argument: " + orientation)
};
using (var document = WordprocessingDocument.Open(fileName, true))
{
if (document?.MainDocumentPart?.Document.Body is null)
{
throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
}
Body docBody = document.MainDocumentPart.Document.Body;
IEnumerable<SectionProperties> sections = docBody.ChildElements.OfType<SectionProperties>();
if (sections.Count() == 0)
{
docBody.AddChild(new SectionProperties());
sections = docBody.ChildElements.OfType<SectionProperties>();
}
Iterar Através de Todas as Secções
O bloco seguinte de código itera todas as secções na coleção de SectionProperties
elementos. Para cada secção, o código inicializa uma variável que controla se a orientação da página da secção foi alterada para que o código possa atualizar o tamanho e as margens da página. (Se a nova orientação corresponder à orientação original, o código não atualizará a página.) O código continua ao obter uma referência para o primeiro PageSize descendente do SectionProperties
elemento. Se a referência não for nula, o código atualiza a orientação conforme necessário.
foreach (SectionProperties sectPr in sections)
{
bool pageOrientationChanged = false;
PageSize pgSz = sectPr.ChildElements.OfType<PageSize>().FirstOrDefault() ?? sectPr.AppendChild(new PageSize() { Width = 12240, Height = 15840 });
Definir a Orientação para a Secção
O bloco de código seguinte verifica primeiro se a Orient propriedade do PageSize
elemento existe. Tal como acontece com muitas propriedades de elementos Open XML, a propriedade ou atributo poderá ainda não existir. Nesse caso, a obtenção da propriedade devolve uma referência nula. Por predefinição, se a propriedade não existir e a nova orientação for Vertical, o código não atualizará a página. Se a Orient
propriedade já existir e o respetivo valor for diferente do novo valor de orientação fornecido como um parâmetro para o método, o código define a Value
propriedade da Orient
propriedade e define o pageOrientationChanged
sinalizador. (O código utiliza o pageOrientationChanged
sinalizador para determinar se tem de atualizar o tamanho e as margens da página.)
Observação
Se o código tiver de criar a Orient
propriedade, também tem de criar o valor a armazenar na propriedade, como uma nova EnumValue<T> instância, fornecendo a nova orientação no EnumValue
construtor.
if (pgSz.Orient is null)
{
// Need to create the attribute. You do not need to
// create the Orient property if the property does not
// already exist, and you are setting it to Portrait.
// That is the default value.
if (newOrientation != PageOrientationValues.Portrait)
{
pageOrientationChanged = true;
pgSz.Orient = new EnumValue<PageOrientationValues>(newOrientation);
}
}
else
{
// The Orient property exists, but its value
// is different than the new value.
if (pgSz.Orient.Value != newOrientation)
{
pgSz.Orient.Value = newOrientation;
pageOrientationChanged = true;
}
Atualizar o Tamanho da Página
Neste ponto do código, a orientação da página pode ter sido alterada. Se for o caso, o código tem de concluir mais duas tarefas. Tem de atualizar o tamanho da página e atualizar as margens da página da secção. A primeira tarefa é fácil: o seguinte código apenas troca a altura e a largura da página, armazenando os valores no PageSize
elemento.
if (pageOrientationChanged)
{
// Changing the orientation is not enough. You must also
// change the page size.
var width = pgSz.Width;
var height = pgSz.Height;
pgSz.Width = height;
pgSz.Height = width;
Atualizar as Margens
O passo seguinte no procedimento de exemplo processa as margens da secção.
Se a orientação da página tiver sido alterada, o código tem de rodar as margens para corresponderem. Para tal, o código obtém uma referência ao PageMargin elemento da secção. Se o elemento existir, o código roda as margens. Tenha em atenção que o código roda as margens em 90 graus— algumas impressoras rodam as margens em 270 graus e pode modificar o código para ter isso em conta.
Tenha também em atenção que as Top propriedades e Bottom do PageMargin
objeto são valores assinados e que as Left propriedades e Right são valores não assinados. O código tem de ser convertido entre os dois tipos de valores à medida que roda as definições de margem, conforme mostrado no código seguinte.
PageMargin? pgMar = sectPr.Descendants<PageMargin>().FirstOrDefault();
if (pgMar is not null)
{
// Rotate margins. Printer settings control how far you
// rotate when switching to landscape mode. Not having those
// settings, this code rotates 90 degrees. You could easily
// modify this behavior, or make it a parameter for the
// procedure.
if (pgMar.Top is null || pgMar.Bottom is null || pgMar.Left is null || pgMar.Right is null)
{
throw new ArgumentNullException("One or more of the PageMargin elements is null.");
}
var top = pgMar.Top.Value;
var bottom = pgMar.Bottom.Value;
var left = pgMar.Left.Value;
var right = pgMar.Right.Value;
pgMar.Top = new Int32Value((int)left);
pgMar.Bottom = new Int32Value((int)right);
pgMar.Left = new UInt32Value((uint)System.Math.Max(0, bottom));
pgMar.Right = new UInt32Value((uint)System.Math.Max(0, top));
}
Código de exemplo
Segue-se o exemplo de código completo SetPrintOrientation
em C# e Visual Basic.
static void SetPrintOrientation(string fileName, string orientation)
{
PageOrientationValues newOrientation = orientation.ToLower() switch
{
"landscape" => PageOrientationValues.Landscape,
"portrait" => PageOrientationValues.Portrait,
_ => throw new System.ArgumentException("Invalid argument: " + orientation)
};
using (var document = WordprocessingDocument.Open(fileName, true))
{
if (document?.MainDocumentPart?.Document.Body is null)
{
throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
}
Body docBody = document.MainDocumentPart.Document.Body;
IEnumerable<SectionProperties> sections = docBody.ChildElements.OfType<SectionProperties>();
if (sections.Count() == 0)
{
docBody.AddChild(new SectionProperties());
sections = docBody.ChildElements.OfType<SectionProperties>();
}
foreach (SectionProperties sectPr in sections)
{
bool pageOrientationChanged = false;
PageSize pgSz = sectPr.ChildElements.OfType<PageSize>().FirstOrDefault() ?? sectPr.AppendChild(new PageSize() { Width = 12240, Height = 15840 });
// No Orient property? Create it now. Otherwise, just
// set its value. Assume that the default orientation is Portrait.
if (pgSz.Orient is null)
{
// Need to create the attribute. You do not need to
// create the Orient property if the property does not
// already exist, and you are setting it to Portrait.
// That is the default value.
if (newOrientation != PageOrientationValues.Portrait)
{
pageOrientationChanged = true;
pgSz.Orient = new EnumValue<PageOrientationValues>(newOrientation);
}
}
else
{
// The Orient property exists, but its value
// is different than the new value.
if (pgSz.Orient.Value != newOrientation)
{
pgSz.Orient.Value = newOrientation;
pageOrientationChanged = true;
}
if (pageOrientationChanged)
{
// Changing the orientation is not enough. You must also
// change the page size.
var width = pgSz.Width;
var height = pgSz.Height;
pgSz.Width = height;
pgSz.Height = width;
PageMargin? pgMar = sectPr.Descendants<PageMargin>().FirstOrDefault();
if (pgMar is not null)
{
// Rotate margins. Printer settings control how far you
// rotate when switching to landscape mode. Not having those
// settings, this code rotates 90 degrees. You could easily
// modify this behavior, or make it a parameter for the
// procedure.
if (pgMar.Top is null || pgMar.Bottom is null || pgMar.Left is null || pgMar.Right is null)
{
throw new ArgumentNullException("One or more of the PageMargin elements is null.");
}
var top = pgMar.Top.Value;
var bottom = pgMar.Bottom.Value;
var left = pgMar.Left.Value;
var right = pgMar.Right.Value;
pgMar.Top = new Int32Value((int)left);
pgMar.Bottom = new Int32Value((int)right);
pgMar.Left = new UInt32Value((uint)System.Math.Max(0, bottom));
pgMar.Right = new UInt32Value((uint)System.Math.Max(0, top));
}
}
}
}
}
}