Solución funcional para el redimensionado de hojas de cálculo
Note
Las hojas de cálculo de Excel incrustadas como objetos OLE en una presentación de PowerPoint mediante componentes Aspose pueden cambiar de tamaño inesperadamente después de su primera activación. Este comportamiento crea una diferencia visual notable entre el objeto OLE antes y después de la activación. Este artículo explica el problema y describe dos formas de solucionarlo.Antecedentes
En el artículo Gestionar OLE, explicamos cómo añadir un marco OLE a una presentación de PowerPoint usando Aspose.Slides for Python via Java. Para abordar el problema de vista previa del objeto, asignamos una imagen del área de la hoja de cálculo seleccionada al marco del objeto OLE. En la presentación resultante, al hacer doble clic en el marco del objeto OLE que muestra la imagen de la hoja, se activa el libro de Excel. Los usuarios pueden realizar los cambios deseados en el libro de Excel real y luego volver a la diapositiva haciendo clic fuera del libro de Excel activado. El tamaño del marco del objeto OLE cambiará cuando el usuario regrese a la diapositiva. El factor de redimensionado variará según el tamaño del marco del objeto OLE y el libro de Excel incrustado.
Causa del redimensionado
Dado que el libro de Excel tiene su propio tamaño de ventana, intenta conservar su tamaño original al activarse por primera vez. Por otro lado, el marco del objeto OLE tiene su propio tamaño. Según Microsoft, cuando se activa el libro de Excel, Excel y PowerPoint negocian el tamaño para asegurar que mantenga las proporciones correctas como parte del proceso de incrustación. El redimensionado ocurre en función de las diferencias entre el tamaño de la ventana de Excel y el tamaño y posición del marco del objeto OLE.
Solución funcional
Existen dos soluciones posibles para evitar el efecto de redimensionado.
- Escalar el marco OLE en la presentación de PowerPoint para que coincida con la altura y anchura totales de las filas y columnas seleccionadas.
- Mantener constante el tamaño del marco OLE y escalar las filas y columnas seleccionadas para que encajen dentro de él.
Escalar el tamaño del marco OLE
Este enfoque establece el tamaño del marco OLE para que coincida con la altura y anchura totales de las filas y columnas seleccionadas en la hoja de cálculo de Excel incrustada.
El ejemplo carga un libro de Excel existente y selecciona las primeras 10 filas y 13 columnas de su primera hoja usando índices basados en cero. WorksheetCollection.setOleSize define el rango mostrado. La vista previa se renderiza a 96 DPI y sus dimensiones en píxeles se convierten a puntos usando 72 puntos por pulgada. ShapeCollection.addOleObjectFrame incrusta el libro modificado en un marco con esas dimensiones. La vista previa se asigna mediante OleObjectFrame.getSubstitutePictureFormat para reemplazar el marcador de posición “EMBEDDED OLE OBJECT” en la presentación guardada.
El asistente de vista previa establece PageSetup.setPrintArea en el rango seleccionado y elimina márgenes, encabezados y pies de página. Con ImageOrPrintOptions.setOnlyArea activado, SheetRender.toImage renderiza el rango como una imagen PNG. El asistente devuelve un nuevo flujo de entrada que contiene la imagen PNG, posicionado al principio para su uso en la presentación.
import jpype
import asposecells
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposecells.api import Workbook, ImageOrPrintOptions, ImageType, SheetRender, CellsUnitType
from asposecells.api import SaveFormat as CellsSaveFormat
from asposeslides.api import Presentation, OleEmbeddedDataInfo, SaveFormat
ByteArrayInputStream = jpype.JClass("java.io.ByteArrayInputStream")
ByteArrayOutputStream = jpype.JClass("java.io.ByteArrayOutputStream")
def create_ole_image(cell_range, image_resolution):
page_setup = cell_range.getWorksheet().getPageSetup()
page_setup.setPrintArea(cell_range.getAddress())
page_setup.setLeftMargin(0)
page_setup.setRightMargin(0)
page_setup.setTopMargin(0)
page_setup.setBottomMargin(0)
page_setup.clearHeaderFooter()
image_options = ImageOrPrintOptions()
image_options.setImageType(ImageType.PNG)
image_options.setVerticalResolution(image_resolution)
image_options.setHorizontalResolution(image_resolution)
image_options.setOnePagePerSheet(True)
image_options.setOnlyArea(True)
sheet_render = SheetRender(cell_range.getWorksheet(), image_options)
image_stream = ByteArrayOutputStream()
try:
sheet_render.toImage(0, image_stream)
image_data = image_stream.toByteArray()
return ByteArrayInputStream(image_data)
finally:
image_stream.close()
start_row, row_count = 0, 10
start_column, column_count = 0, 13
worksheet_index = 0
image_resolution = 96
workbook = Workbook("sample.xlsx")
try:
worksheet = workbook.getWorksheets().get(worksheet_index)
# Establecer el tamaño mostrado cuando el libro se usa como objeto OLE en PowerPoint.
last_row = start_row + row_count - 1
last_column = start_column + column_count - 1
workbook.getWorksheets().setOleSize(start_row, last_row, start_column, last_column)
cell_range = worksheet.getCells().createRange(start_row, start_column, row_count, column_count)
image_stream = create_ole_image(cell_range, image_resolution)
try:
# Obtener el ancho y la altura de la imagen OLE en puntos.
image_io = jpype.JClass("javax.imageio.ImageIO")
image = image_io.read(image_stream)
frame_width = image.getWidth() * 72.0 / image_resolution
frame_height = image.getHeight() * 72.0 / image_resolution
# Utilizar el libro modificado.
ole_stream = ByteArrayOutputStream()
try:
workbook.save(ole_stream, CellsSaveFormat.XLSX)
workbook_data = ole_stream.toByteArray()
finally:
ole_stream.close()
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
# Añadir la imagen OLE a los recursos de la presentación.
image_stream.reset()
ole_image = presentation.getImages().addImage(image_stream)
# Crear el marco del objeto OLE.
data_info = OleEmbeddedDataInfo(workbook_data, "xlsx")
ole_frame = slide.getShapes().addOleObjectFrame(10.0, 10.0, frame_width, frame_height, data_info)
ole_frame.getSubstitutePictureFormat().getPicture().setImage(ole_image)
ole_frame.setObjectIcon(False)
presentation.save("output.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
finally:
image_stream.close()
finally:
workbook.dispose()
Escalar el tamaño del rango de celdas
Este enfoque escala las alturas de las filas seleccionadas y las anchuras de las columnas seleccionadas para que coincidan con un tamaño de marco OLE personalizado.
El ejemplo carga un libro de Excel existente y selecciona las primeras 10 filas y 13 columnas de su primera hoja usando índices basados en cero. WorksheetCollection.setOleSize define el rango mostrado, y el asistente scale_cell_range escala ese rango para que encaje en un marco de 400 puntos de ancho y 100 puntos de alto. Después de guardar el libro modificado en un flujo, ShapeCollection.addOleObjectFrame lo incrusta con el tamaño especificado. Una vista previa renderizada a 96 DPI se asigna mediante OleObjectFrame.getSubstitutePictureFormat, de modo que la presentación guardada muestre las celdas seleccionadas en lugar del marcador de posición predeterminado.
El asistente de escalado calcula ratios de ancho y alto por separado para el rango seleccionado, preservando las anchuras relativas de sus columnas y las alturas relativas de sus filas. Convierte las dimensiones calculadas de puntos a pulgadas antes de aplicarlas con Cells.setColumnWidthInch y Cells.setRowHeightInch. El rango seleccionado debe tener ancho y alto distintos de cero.
Este asistente de vista previa renderiza el rango redimensionado usando SheetRender.toImage. Limita PageSetup.setPrintArea a ese rango, elimina márgenes, encabezados y pies de página, y devuelve un flujo PNG posicionado al principio.
import jpype
import asposecells
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposecells.api import Workbook, ImageOrPrintOptions, ImageType, SheetRender, CellsUnitType
from asposecells.api import SaveFormat as CellsSaveFormat
from asposeslides.api import Presentation, OleEmbeddedDataInfo, SaveFormat
ByteArrayInputStream = jpage.JClass("java.io.ByteArrayInputStream")
ByteArrayOutputStream = jpage.JClass("java.io.ByteArrayOutputStream")
def create_ole_image(cell_range, image_resolution):
page_setup = cell_range.getWorksheet().getPageSetup()
page_setup.setPrintArea(cell_range.getAddress())
page_setup.setLeftMargin(0)
page_setup.setRightMargin(0)
page_setup.setTopMargin(0)
page_setup.setBottomMargin(0)
page_setup.clearHeaderFooter()
image_options = ImageOrPrintOptions()
image_options.setImageType(ImageType.PNG)
image_options.setVerticalResolution(image_resolution)
image_options.setHorizontalResolution(image_resolution)
image_options.setOnePagePerSheet(True)
image_options.setOnlyArea(True)
sheet_render = SheetRender(cell_range.getWorksheet(), image_options)
image_stream = ByteArrayOutputStream()
try:
sheet_render.toImage(0, image_stream)
image_data = image_stream.toByteArray()
return ByteArrayInputStream(image_data)
finally:
image_stream.close()
def scale_cell_range(cell_range, width, height):
# Se espera que el ancho y la altura del rango de celdas estén en puntos.
range_width = cell_range.getWidth()
range_height = cell_range.getHeight()
cells = cell_range.getWorksheet().getCells()
for i in range(cell_range.getColumnCount()):
column_index = cell_range.getFirstColumn() + i
column_width = cells.getColumnWidth(column_index, False, CellsUnitType.POINT)
new_column_width = column_width * width / range_width
width_in_inches = new_column_width / 72.0
cells.setColumnWidthInch(column_index, width_in_inches)
for i in range(cell_range.getRowCount()):
row_index = cell_range.getFirstRow() + i
row_height = cells.getRowHeight(row_index, False, CellsUnitType.POINT)
new_row_height = row_height * height / range_height
height_in_inches = new_row_height / 72.0
cells.setRowHeightInch(row_index, height_in_inches)
start_row, row_count = 0, 10
start_column, column_count = 0, 13
worksheet_index = 0
image_resolution = 96
frame_width, frame_height = 400.0, 100.0
workbook = Workbook("sample.xlsx")
try:
worksheet = workbook.getWorksheets().get(worksheet_index)
# Establecer el tamaño mostrado cuando el libro se usa como objeto OLE en PowerPoint.
last_row = start_row + row_count - 1
last_column = start_column + column_count - 1
workbook.getWorksheets().setOleSize(start_row, last_row, start_column, last_column)
cell_range = worksheet.getCells().createRange(start_row, start_column, row_count, column_count)
# Escalar el rango de celdas para que encaje en el tamaño del marco.
scale_cell_range(cell_range, frame_width, frame_height)
image_stream = create_ole_image(cell_range, image_resolution)
try:
# Utilizar el libro modificado.
ole_stream = ByteArrayOutputStream()
try:
workbook.save(ole_stream, CellsSaveFormat.XLSX)
workbook_data = ole_stream.toByteArray()
finally:
ole_stream.close()
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
# Añadir la imagen OLE a los recursos de la presentación.
image_stream.reset()
ole_image = presentation.getImages().addImage(image_stream)
# Crear el marco del objeto OLE.
data_info = OleEmbeddedDataInfo(workbook_data, "xlsx")
ole_frame = slide.getShapes().addOleObjectFrame(10.0, 10.0, frame_width, frame_height, data_info)
ole_frame.getSubstitutePictureFormat().getPicture().setImage(ole_image)
ole_frame.setObjectIcon(False)
presentation.save("output.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
finally:
image_stream.close()
finally:
workbook.dispose()
Conclusión
Note
Existen dos enfoques para corregir el problema de redimensionado de la hoja de cálculo. Elija el enfoque que mejor se adapte a sus requisitos y caso de uso. Ambos enfoques funcionan de la misma manera, ya sea que las presentaciones se creen a partir de una plantilla o desde cero. Además, no hay límite de tamaño para el marco del objeto OLE en esta solución.Preguntas frecuentes
¿Por qué una hoja de cálculo de Excel incrustada cambia de tamaño al activarse por primera vez en PowerPoint?
Esto ocurre porque Excel intenta mantener el tamaño original de la ventana al activarse, mientras que el marco del objeto OLE en PowerPoint tiene sus propias dimensiones. PowerPoint y Excel negocian el tamaño para mantener la relación de aspecto, lo que puede provocar el redimensionado.
¿Es posible evitar por completo este problema de redimensionado?
Sí. Al escalar el marco OLE para que se ajuste al tamaño del rango de celdas de Excel o al escalar el rango de celdas para que se ajuste al tamaño deseado del marco OLE, se puede evitar el redimensionado no deseado.
¿Qué método de escalado debo usar, escalado del marco OLE o escalado del rango de celdas?
Seleccione escalado del marco OLE si desea mantener los tamaños originales de filas y columnas de Excel. Seleccione escalado del rango de celdas si desea un tamaño fijo para el marco OLE en su presentación.
¿Funcionarán estas soluciones si mi presentación se basa en una plantilla?
Sí. Ambas soluciones funcionan para presentaciones creadas a partir de plantillas y desde cero.
¿Existe un límite para el tamaño del marco OLE al utilizar estos métodos?
No. Puede definir el marco del objeto OLE con cualquier tamaño siempre que ajuste la escala de manera adecuada.
¿Hay alguna forma de evitar el texto de marcador de posición “EMBEDDED OLE OBJECT” en PowerPoint?
Sí. Tomando una captura del rango de celdas de Excel objetivo y configurándola como la imagen del marcador de posición del marco OLE, puede mostrar una imagen de vista previa personalizada en lugar del marcador de posición predeterminado.
Artículos relacionados
Crear un gráfico de Excel e incrustarlo en una presentación como objeto OLE
Actualizar objetos OLE automáticamente usando un complemento de MS PowerPoint