Gestionar temas de presentación en Python vía Java

Introducción

Un tema de presentación define un conjunto coordinado de colores, fuentes, estilos de fondo, rellenos, líneas y efectos. Los objetos compatibles con temas hacen referencia a estas definiciones compartidas en lugar de almacenar cada propiedad visual como un valor fijo, de modo que un cambio de tema pueda actualizar muchos objetos a la vez.

En Aspose.Slides, el tema a nivel de presentación está disponible a través de Presentation.getMasterTheme. Una presentación también puede contener anulaciones de tema en niveles inferiores. Un master puede anular el tema de la presentación mediante MasterThemeManager.getOverrideTheme, mientras que un diseño o una diapositiva individual pueden anular su tema heredado mediante BaseOverrideThemeManager.getOverrideTheme. En la práctica, el tema efectivo para una diapositiva se resuelve a través de esta cadena de herencia: tema de la presentación, anulación del master, anulación del diseño y anulación de la diapositiva.

Componentes del tema: colores, fuentes, estilos de fondo y efectos

Las secciones a continuación muestran los flujos de trabajo de tema más habituales: inspeccionar un tema, cambiar colores y fuentes, copiar o aplicar un tema, actualizar estilos de fondo y de efecto, y leer los valores efectivos después de que la herencia y las anulaciones se hayan resuelto.

Inspeccionar un tema

El objeto MasterTheme expone el esquema de colores, el esquema de fuentes y el esquema de formato del tema a través de MasterTheme.getColorScheme, MasterTheme.getFontScheme y MasterTheme.getFormatScheme. Inspeccionar estas colecciones antes de modificarlas es especialmente útil cuando una presentación proviene de una fuente externa, ya que el número y el contenido de las entradas de estilo pueden variar.

El siguiente ejemplo lee las propiedades principales del tema y muestra cuántos estilos de fondo, relleno, línea y efecto están almacenados en el tema:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import Presentation

presentation = Presentation("input.pptx")
try:
    theme = presentation.getMasterTheme()
    print("Theme name:", theme.getName())
    print("Accent 1:", theme.getColorScheme().getAccent1().getColor())
    print("Major Latin font:", theme.getFontScheme().getMajor().getLatinFont().getFontName())
    print("Minor Latin font:", theme.getFontScheme().getMinor().getLatinFont().getFontName())
    print("Background fill styles:", theme.getFormatScheme().getBackgroundFillStyles().size())
    print("Fill styles:", theme.getFormatScheme().getFillStyles().size())
    print("Line styles:", theme.getFormatScheme().getLineStyles().size())
    print("Effect styles:", theme.getFormatScheme().getEffectStyles().size())
finally:
    presentation.dispose()

Si un archivo utiliza varios masters, no asuma que cada diapositiva tiene el mismo tema efectivo. Inspeccione el master asociado a la diapositiva y use el flujo de trabajo de tema efectivo que se muestra más adelante en este artículo cuando puedan existir anulaciones de diseño o de diapositiva.

Cambiar colores del tema

Los rellenos, líneas y textos compatibles con temas pueden referirse a un color lógico de la enumeración SchemeColor. Cuando cambia la entrada correspondiente en el ColorScheme, todos los objetos que todavía hacen referencia a ese color de tema se resuelven contra el nuevo valor. Los objetos que utilizan un color RGB directo no se modifican con una actualización de color de tema.

El siguiente ejemplo de extremo a extremo crea una forma que usa Accent4, cambia el color Accent4 del tema a rojo, guarda la presentación, la vuelve a abrir y muestra el color de relleno efectivo:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import FillType, Presentation, SaveFormat, SchemeColor, ShapeType
from java.awt import Color

presentation = Presentation()
try:
    slide = presentation.getSlides().get_Item(0)
    shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 10, 100, 100)
    shape.getFillFormat().setFillType(FillType.Solid)
    shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)
    presentation.getMasterTheme().getColorScheme().getAccent4().setColor(Color.RED)
    presentation.save("theme-color.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

saved_presentation = Presentation("theme-color.pptx")
try:
    saved_slide = saved_presentation.getSlides().get_Item(0)
    saved_shape = saved_slide.getShapes().get_Item(0)
    effective_fill = saved_shape.getFillFormat().getEffective()
    print("Effective fill color:", effective_fill.getSolidFillColor())
finally:
    saved_presentation.dispose()

Porque el rectángulo sigue vinculado a Accent4, su color visible se vuelve rojo después de cambiar el tema. Si sustituye el color del esquema por un color directo en la forma, los cambios posteriores de Accent4 ya no afectarán a ese relleno.

Usar colores de la paleta adicional

PowerPoint genera variantes más claras y más oscuras a partir de un color de tema aplicando transformaciones de color. Aspose.Slides expone estas transformaciones a través de la enumeración ColorTransformOperation.

Colores principales del tema y colores más claros y más oscuros generados a partir de la paleta adicional

1 - Colores principales del tema.
2 - Variantes más claras y más oscuras producidas a partir de los colores principales del tema.

El siguiente ejemplo crea seis rectángulos basados en Accent4, aplica transformaciones de luminancia a cinco de ellos y guarda el resultado:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import ColorTransformOperation, FillType, Presentation, SaveFormat, SchemeColor, ShapeType

presentation = Presentation()
try:
    slide = presentation.getSlides().get_Item(0)

    base_shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 10, 50, 50)
    base_shape.getFillFormat().setFillType(FillType.Solid)
    base_shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)

    lightest_shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 70, 50, 50)
    lightest_shape.getFillFormat().setFillType(FillType.Solid)
    lightest_shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)
    lightest_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.MultiplyLuminance, 0.2)
    lightest_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.AddLuminance, 0.8)

    lighter_shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 130, 50, 50)
    lighter_shape.getFillFormat().setFillType(FillType.Solid)
    lighter_shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)
    lighter_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.MultiplyLuminance, 0.4)
    lighter_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.AddLuminance, 0.6)

    light_shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 190, 50, 50)
    light_shape.getFillFormat().setFillType(FillType.Solid)
    light_shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)
    light_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.MultiplyLuminance, 0.6)
    light_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.AddLuminance, 0.4)

    dark_shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 250, 50, 50)
    dark_shape.getFillFormat().setFillType(FillType.Solid)
    dark_shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)
    dark_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.MultiplyLuminance, 0.75)

    darker_shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 310, 50, 50)
    darker_shape.getFillFormat().setFillType(FillType.Solid)
    darker_shape.getFillFormat().getSolidFillColor().setSchemeColor(SchemeColor.Accent4)
    darker_shape.getFillFormat().getSolidFillColor().getColorTransform().add(ColorTransformOperation.MultiplyLuminance, 0.5)

    presentation.save("theme-color-palette.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

Estas variantes siguen basadas en el color del tema. Si Accent4 cambia después, los colores transformados se recalculan a partir del nuevo valor de Accent4.

Asignar valores de SchemeColor a ranuras de ColorScheme

La enumeración SchemeColor utiliza Text1, Background1, Text2 y Background2, mientras que el ColorScheme expone las mismas ranuras del tema como Dark1, Light1, Dark2 y Light2. La asignación es fija:

  • Text1 = Dark1
  • Background1 = Light1
  • Text2 = Dark2
  • Background2 = Light2

Estos son nombres alternativos para las mismas ranuras del tema; no son valores que se conviertan dinámicamente de una forma a otra.

Cambiar fuentes del tema

Un esquema de fuentes del tema contiene un conjunto de fuentes principal para los encabezados y un conjunto de fuentes secundario para el cuerpo del texto. Los métodos FontScheme.getMajor y FontScheme.getMinor exponen esos conjuntos.

Los identificadores de fuentes de tema compatibles con PowerPoint pueden usarse en el formato de texto:

  • +mn-lt - Fuente del cuerpo latín (Minor Latin Font)
  • +mj-lt - Fuente del encabezado latín (Major Latin Font)
  • +mn-ea - Fuente del cuerpo asiática oriental (Minor East Asian Font)
  • +mj-ea - Fuente del encabezado asiática oriental (Major East Asian Font)

El siguiente ejemplo crea un encabezado que usa la fuente latina mayor del tema y una línea de cuerpo que usa la fuente latina menor del tema. Luego cambia las fuentes del tema y guarda el resultado:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import FontData, Presentation, SaveFormat, ShapeType

presentation = Presentation()
try:
    slide = presentation.getSlides().get_Item(0)

    heading = slide.getShapes().addAutoShape(ShapeType.Rectangle, 40, 40, 500, 60)
    heading.getTextFrame().setText("Theme heading")
    font_data = FontData("+mj-lt")
    heading.getTextFrame().getParagraphs().get_Item(0).getPortions().get_Item(0).getPortionFormat().setLatinFont(font_data)

    body = slide.getShapes().addAutoShape(ShapeType.Rectangle, 40, 120, 500, 60)
    body.getTextFrame().setText("Theme body text")
    font_data = FontData("+mn-lt")
    body.getTextFrame().getParagraphs().get_Item(0).getPortions().get_Item(0).getPortionFormat().setLatinFont(font_data)

    font_data = FontData("Aptos Display")
    presentation.getMasterTheme().getFontScheme().getMajor().setLatinFont(font_data)
    font_data = FontData("Arial")
    presentation.getMasterTheme().getFontScheme().getMinor().setLatinFont(font_data)
    presentation.save("theme-fonts.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

El encabezado sigue la fuente mayor y el texto del cuerpo sigue la fuente menor. El texto que tenga un nombre de fuente explícito en lugar de un identificador de tema no cambiará automáticamente cuando el esquema de fuentes del tema cambie.

Las colecciones de fuentes mayor y menor también pueden contener asignaciones de fuentes para sistemas de escritura individuales, como cirílico, árabe, japonés, georgiano y thaana. Para inspeccionar, agregar, sustituir o eliminar estas asignaciones, consulte Fuentes de tema específicas del script.

Copiar o aplicar un tema

Los flujos de trabajo a continuación resuelven diferentes problemas relacionados con temas.

Aplicar un tema externo a diapositivas dependientes de un master

Use MasterSlide.applyExternalThemeToDependingSlides cuando disponga de un archivo de tema de PowerPoint (.thmx) y desee reutilizar el estilo de todas las diapositivas que dependen de un master concreto. Seleccione el master de la colección Presentation.getMasters, representada por MasterSlideCollection, y pase la ruta del archivo de tema al método.

El método realiza las siguientes operaciones:

  1. Crea una nueva diapositiva master basada en el master seleccionado.
  2. Aplica el tema externo al nuevo master.
  3. Asigna el nuevo master a todas las diapositivas que previamente dependían del master seleccionado.
  4. Devuelve el MasterSlide recién creado.

El siguiente ejemplo aplica un tema externo a las diapositivas que dependen del primer master y guarda la presentación:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import Presentation, SaveFormat

presentation = Presentation("presentation.pptx")
try:
    selected_master = presentation.getMasters().get_Item(0)
    themed_master = selected_master.applyExternalThemeToDependingSlides("corporate-theme.thmx")

    print("Created master:", themed_master.getName())
    presentation.save("presentation-with-external-theme.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

Un tema inválido, dañado o no compatible puede generar PptxReadException. Valide las rutas suministradas por los usuarios, gestione los fallos de acceso al sistema de archivos y guarde la presentación solo después de que el tema se haya aplicado con éxito.

Solo se reasignan las diapositivas que dependían del master seleccionado. Las diapositivas asociadas a otros masters conservan sus masters y temas actuales. Los colores, fuentes, rellenos, líneas, fondos y efectos compatibles con temas se resuelven contra el tema externo. Los colores, fuentes, rellenos y otros formatos asignados directamente pueden permanecer sin cambios. Las anulaciones a nivel de diseño y de diapositiva también pueden tener prioridad sobre los valores heredados del nuevo master.

El tema puede hacer referencia a fuentes que no estén disponibles en el entorno de ejecución. Para una representación y exportación coherentes, instale las fuentes requeridas, proporciónelas mediante fuentes personalizadas, o configure la sustitución de fuentes.

Este es un flujo de trabajo directo a nivel de master: el método acepta la ruta de un archivo .thmx y no requiere crear manualmente anulaciones de tema a nivel de diseño o de diapositiva.

Aplicar diferentes temas externos en una presentación con varios masters

Cuando el master relevante no se conoce de antemano, obténgalo a partir de una diapositiva representativa mediante Slide.getLayoutSlide y LayoutSlide.getMasterSlide. Guarde las referencias originales de los masters antes de aplicar cualquier tema porque cada llamada crea otro master en la presentación.

El siguiente ejemplo utiliza diapositivas de dos secciones para localizar sus masters y aplica un tema externo diferente a cada grupo:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import Presentation, SaveFormat

presentation = Presentation("multi-master-presentation.pptx")
try:
    if presentation.getSlides().size() < 5:
        print("The presentation does not contain the expected representative slides.")
    else:
        first_group_master = presentation.getSlides().get_Item(0).getLayoutSlide().getMasterSlide()
        second_group_master = presentation.getSlides().get_Item(4).getLayoutSlide().getMasterSlide()

        if first_group_master.getSlideId() == second_group_master.getSlideId():
            print("The representative slides use the same master.")
        else:
            first_themed_master = first_group_master.applyExternalThemeToDependingSlides("blue-theme.thmx")
            second_themed_master = second_group_master.applyExternalThemeToDependingSlides("green-theme.thmx")

            print("First themed master:", first_themed_master.getName())
            print("Second themed master:", second_themed_master.getName())
            presentation.save("multi-master-with-external-themes.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

La primera llamada afecta solo a las diapositivas que dependían de first_group_master, y la segunda llamada afecta solo a las diapositivas que dependían de second_group_master. Las diapositivas pertenecientes a cualquier otro master no se vuelven a estilizar.

Conservar un tema de origen al mover diapositivas

Si desea mover una diapositiva a otra presentación y conservar su diseño original, clone el master de origen en la presentación de destino con MasterSlideCollection.addClone, y luego clone la diapositiva con SlideCollection.addClone y el master clonado. Esto transporta el master, sus diseños y el tema asociado juntos.

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import Presentation, SaveFormat

source = Presentation("source-theme.pptx")
try:
    target = Presentation("target.pptx")
    try:
        source_slide = source.getSlides().get_Item(0)
        source_master = source_slide.getLayoutSlide().getMasterSlide()
        cloned_master = target.getMasters().addClone(source_master)
        target.getSlides().addClone(source_slide, cloned_master, True)
        target.save("theme-preserved.pptx", SaveFormat.Pptx)
    finally:
        target.dispose()
finally:
    source.dispose()

Este es el flujo de trabajo preferido cuando la diapositiva de origen debe verse igual en el destino. Simplemente clonar el contenido sobre un master de destino no relacionado puede cambiar los colores, fuentes, fondos y efectos impulsados por el tema.

Aplicar valores de tema a una diapositiva existente

Si la diapositiva de destino debe permanecer en su master y diseño actuales, inicialice una anulación a nivel de diapositiva a partir del tema de origen. Los métodos OverrideTheme.initColorSchemeFrom, OverrideTheme.initFontSchemeFrom y OverrideTheme.initFormatSchemeFrom copian los tres componentes principales del tema en la anulación.

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import Presentation, SaveFormat

source = Presentation("source-theme.pptx")
try:
    target = Presentation("target.pptx")
    try:
        target_slide = target.getSlides().get_Item(0)
        override_theme = target_slide.getThemeManager().getOverrideTheme()
        override_theme.initColorSchemeFrom(source.getMasterTheme().getColorScheme())
        override_theme.initFontSchemeFrom(source.getMasterTheme().getFontScheme())
        override_theme.initFormatSchemeFrom(source.getMasterTheme().getFormatScheme())
        target.save("theme-applied-to-slide.pptx", SaveFormat.Pptx)
    finally:
        target.dispose()
finally:
    source.dispose()

Esto cambia el tema usado por esa diapositiva sin modificar el tema heredado por otras diapositivas. Para eliminar la anulación local y volver a los valores heredados, llame a OverrideTheme.clear.

Aplicar una anulación de tema a un diseño

Una anulación a nivel de diseño se aplica a las diapositivas que usan ese diseño, salvo que una diapositiva concreta tenga su propia anulación. Los mismos métodos de inicialización pueden usarse a través de LayoutSlideThemeManager:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import Presentation, SaveFormat

source = Presentation("source-theme.pptx")
try:
    target = Presentation("target.pptx")
    try:
        target_slide = target.getSlides().get_Item(0)
        target_layout = target_slide.getLayoutSlide()
        override_theme = target_layout.getThemeManager().getOverrideTheme()
        override_theme.initColorSchemeFrom(source.getMasterTheme().getColorScheme())
        override_theme.initFontSchemeFrom(source.getMasterTheme().getFontScheme())
        override_theme.initFormatSchemeFrom(source.getMasterTheme().getFormatScheme())
        target.save("theme-applied-to-layout.pptx", SaveFormat.Pptx)
    finally:
        target.dispose()
finally:
    source.dispose()

Use un tema a nivel de master o de presentación cuando muchos diseños y diapositivas deben compartir el mismo diseño base, una anulación de diseño cuando una familia de diseños necesita un estilo diferente, y una anulación de diapositiva solo para excepciones reales. Un exceso de anulaciones a nivel de diapositiva dificulta la predicción de cambios globales de tema posteriores.

Actualizar estilos de fondo del tema

Los rellenos de fondo del tema se almacenan en FormatScheme.getBackgroundFillStyles. PowerPoint puede presentar más opciones de fondo en su interfaz de usuario que el número de definiciones de relleno almacenadas físicamente en esta colección, porque la UI puede combinar rellenos de tema con colores de tema y otras referencias de estilo.

Galería de estilos de fondo de PowerPoint para un tema de presentación

Antes de usar un estilo de fondo, inspeccione la colección almacenada y el Background.getStyleIndex actual. Un índice de estilo de 0 indica que no hay relleno temático; los valores positivos son referencias a estilos de fondo del tema. Esto difiere de indexar directamente la colección, donde get_Item(0) significa el primer elemento almacenado. No asuma que todas las presentaciones contengan el mismo número de estilos de relleno de fondo.

El siguiente ejemplo muestra el recuento de rellenos de fondo disponibles, asigna una referencia de fondo temático al primer master y guarda la presentación:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import BackgroundType, Presentation, SaveFormat

presentation = Presentation("input.pptx")
try:
    background_styles = presentation.getMasterTheme().getFormatScheme().getBackgroundFillStyles()
    print("Background fill styles:", background_styles.size())
    if background_styles.size() == 0:
        print("The presentation theme does not contain background fill styles.")
    else:
        master_slide = presentation.getMasters().get_Item(0)
        master_slide.getBackground().setType(BackgroundType.Themed)
        master_slide.getBackground().setStyleIndex(1)
        presentation.save("theme-background.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

El resultado visible depende de la entrada del tema referenciada por el master y de cualquier anulación de fondo a nivel de diseño o de diapositiva. Si una diapositiva usa su propio fondo, cambiar solo el fondo del master puede no afectar a esa diapositiva. Use Background.getEffective cuando necesite conocer el fondo final tras aplicar la herencia.

Actualizar efectos del tema

Un esquema de formato del tema contiene colecciones independientes de relleno, línea y efecto accesibles mediante FormatScheme.getFillStyles, FormatScheme.getLineStyles y FormatScheme.getEffectStyles. Los temas típicos de Office suelen contener tres entradas principales que corresponden visualmente a formatos sutil, moderado e intenso, pero el código debe inspeccionar cada colección en lugar de asumir un recuento fijo.

Efectos de tema sutil, moderado e intenso aplicados a la misma forma

Al acceder a estas colecciones en Python mediante Java, el índice de la colección es cero basado: get_Item(0) es el primer estilo almacenado y get_Item(2) el tercero. Los índices de referencia de estilo de una forma son un concepto separado, expuesto a través de ShapeStyle. Modificar un estilo de tema afecta a las formas que hacen referencia a ese estilo; las formas con formato directo pueden permanecer sin cambios.

El siguiente ejemplo verifica que existan las entradas de estilo requeridas, cambia el primer estilo de línea, cambia el tercer estilo de relleno, habilita una sombra exterior en el tercer estilo de efecto y guarda el resultado:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import FillType, Presentation, SaveFormat
from java.awt import Color

presentation = Presentation("Subtle_Moderate_Intense.pptx")
try:
    format_scheme = presentation.getMasterTheme().getFormatScheme()
    if format_scheme.getLineStyles().size() < 1 or format_scheme.getFillStyles().size() < 3 or format_scheme.getEffectStyles().size() < 3:
        print("The theme does not contain the style entries required by this example.")
    else:
        format_scheme.getLineStyles().get_Item(0).getFillFormat().setFillType(FillType.Solid)
        format_scheme.getLineStyles().get_Item(0).getFillFormat().getSolidFillColor().setColor(Color.RED)
        format_scheme.getFillStyles().get_Item(2).setFillType(FillType.Solid)
        forest_green = Color(34, 139, 34)
        format_scheme.getFillStyles().get_Item(2).getSolidFillColor().setColor(forest_green)
        effect_format = format_scheme.getEffectStyles().get_Item(2).getEffectFormat()
        effect_format.enableOuterShadowEffect()
        effect_format.getOuterShadowEffect().setDistance(10)
        presentation.save("theme-effects.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

Para las formas que hacen referencia a estas ranuras, el primer estilo de línea del tema se vuelve rojo, el tercer estilo de relleno del tema se vuelve verde bosque sólido y el tercer estilo de efecto adquiere una sombra exterior con una distancia de 10 puntos. El resultado visual exacto sigue dependiendo de qué ranuras de estilo referencia cada forma y de si el formato directo anula el tema.

Estilos de efecto del tema después de modificar línea, relleno y sombra

Determinar si un relleno sólido efectivo usa un color de tema

Un relleno puede almacenarse directamente en un objeto o heredarse de un párrafo, diseño, master, estilo de tema u otro nivel de formato. Llame a FillFormat.getEffective para resolver esa jerarquía en datos de relleno efectivos inmutables. Primero compruebe getFillType en el objeto de datos efectivo. Solo cuando sea FillType.Solid debe leer las propiedades del relleno sólido.

Para un relleno sólido, getSolidFillColor devuelve el valor RGB final renderizado después de aplicar herencia, búsqueda en el tema y transformaciones de color. getSolidFillSchemeColor devuelve la ranura lógica correspondiente de SchemeColor, como Text1 o Accent6. Un valor de SchemeColor.NotDefined indica que el relleno sólido efectivo no se basa en un color de esquema. En un flujo de trabajo donde los rellenos son colores de tema o colores RGB directos, este valor identifica un relleno RGB directo.

No utilice solo el valor local de ColorFormat.getSchemeColor para clasificar un relleno. Por ejemplo, una porción de texto puede no tener un color de esquema definido localmente, por lo que su valor local es NotDefined, mientras que su relleno efectivo hereda un color de tema y se resuelve a Text1 o Accent6. En cambio, getSolidFillSchemeColor le indica qué ranura lógica del tema produjo el color efectivo, pero no le dice si esa ranura provino del objeto, párrafo, diseño, master u otro nivel de la jerarquía de formato.

El siguiente ejemplo carga una presentación, audita tanto los rellenos de forma como los rellenos de porciones de texto, muestra cada valor RGB final y el color de esquema asociado, y marca los rellenos sólidos que no seguirán los cambios de color del tema:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import AutoShape, FillType, Presentation, SchemeColor

def audit_fill(object_name, local_fill):
    effective_fill = local_fill.getEffective()
    if effective_fill.getFillType() != FillType.Solid:
        print(f"{object_name}: fill type = {effective_fill.getFillType()}; not a solid fill.")
        return

    rgb = effective_fill.getSolidFillColor()
    effective_scheme_color = effective_fill.getSolidFillSchemeColor()
    local_scheme_color = local_fill.getSolidFillColor().getSchemeColor()
    print(f"{object_name}: RGB = #{rgb.getRed():02X}{rgb.getGreen():02X}{rgb.getBlue():02X}")
    print(f"{object_name}: local scheme = {local_scheme_color}, effective scheme = {effective_scheme_color}")
    if effective_scheme_color == SchemeColor.NotDefined:
        print(f"{object_name}: direct RGB or another non-scheme fill; audit as theme-independent.")
    else:
        print(f"{object_name}: theme-dependent through {effective_scheme_color}.")


presentation = Presentation("input.pptx")
try:
    for slide_index, slide in enumerate(presentation.getSlides()):
        for shape_index, shape in enumerate(slide.getShapes()):
            shape_name = f"Slide {slide_index + 1}, shape {shape_index + 1}"
            audit_fill(shape_name, shape.getFillFormat())
            if isinstance(shape, AutoShape):
                for paragraph_index, paragraph in enumerate(shape.getTextFrame().getParagraphs()):
                    for portion_index, portion in enumerate(paragraph.getPortions()):
                        portion_name = f"{shape_name}, paragraph {paragraph_index + 1}, portion {portion_index + 1}"
                        audit_fill(portion_name, portion.getPortionFormat().getFillFormat())
finally:
    presentation.dispose()

La rama NotDefined proporciona una lista de auditoría de rellenos sólidos que no responderán a cambios en las ranuras de color del tema. Revise esos objetos cuando una presentación deba adherirse a una nueva paleta de marca. El valor RGB informado sigue mostrando la apariencia actual, mientras que el valor de esquema explica si esa apariencia está conectada al tema.

Los objetos de formato efectivo son instantáneas. Después de cambiar el tema de la presentación, una anulación de tema o cualquier formato heredado, vuelva a llamar a getEffective y lea un nuevo objeto de datos de relleno efectivo antes de comparar o informar colores.

Leer valores efectivos del tema

Los objetos de tema sin procesar le indican lo que está definido en un nivel determinado. Los valores efectivos le indican lo que una diapositiva o forma usa realmente después de que la herencia y las anulaciones locales se hayan resuelto. Para una diapositiva, llame a BaseOverrideThemeManager.createThemeEffective. Para un fondo, use Background.getEffective, y para un relleno, use FillFormat.getEffective.

El siguiente ejemplo lee el tema efectivo, el fondo y el primer relleno de forma de una diapositiva:

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import FillType, Presentation

presentation = Presentation("input.pptx")
try:
    slide = presentation.getSlides().get_Item(0)
    effective_theme = slide.getThemeManager().createThemeEffective()
    effective_background = slide.getBackground().getEffective()
    print("Effective major Latin font:", effective_theme.getFontScheme().getMajor().getLatinFont().getFontName())
    print("Effective minor Latin font:", effective_theme.getFontScheme().getMinor().getLatinFont().getFontName())
    print("Effective background fill type:", effective_background.getFillFormat().getFillType())
    if slide.getShapes().size() > 0:
        effective_fill = slide.getShapes().get_Item(0).getFillFormat().getEffective()
        print("First shape effective fill type:", effective_fill.getFillType())
        if effective_fill.getFillType() == FillType.Solid:
            print("First shape effective fill color:", effective_fill.getSolidFillColor())
finally:
    presentation.dispose()

Utilice los datos efectivos para diagnósticos de renderizado, validación y comparaciones. Si solo inspecciona Presentation.getMasterTheme, puede pasar por alto una anulación de master, diseño, diapositiva o forma que cambie la apariencia final.

Preguntas frecuentes

¿Aplicar un tema externo afecta a todas las diapositivas de la presentación?

No. MasterSlide.applyExternalThemeToDependingSlides reasigna solo las diapositivas que dependen del master seleccionado. Las diapositivas que usan otros masters conservan sus temas actuales.

¿Puedo aplicar un tema a una sola diapositiva sin cambiar el master?

Sí. Utilice el SlideThemeManager de la diapositiva e inicialice su tema de anulación. El cambio permanece local a esa diapositiva; las demás continúan heredando sus temas actuales.

¿Cuál es la forma más segura de trasladar un tema de una presentación a otra?

Al mover una diapositiva y conservar su apariencia original, clone el master de origen en el destino y clone la diapositiva con ese master usando MasterSlideCollection.addClone y SlideCollection.addClone. Esto mantiene juntos el master, los diseños y el tema.

¿Cómo puedo ver los valores efectivos después de la herencia y las anulaciones?

Utilice BaseOverrideThemeManager.createThemeEffective para un tema de diapositiva o de diseño y los métodos de datos efectivos correspondientes para objetos de formato, como Background.getEffective y FillFormat.getEffective. Estas API devuelven los valores resueltos tras aplicar la herencia y las anulaciones.