Manipulating TIFF Images
Add Frames with Different Settings
TIFF is a very flexible format and it allows different frames to be added, with different dimensions, compression and other settings. Aspose.Imaging APIs allow you to add any TIFF frame of any size which helps in creating complex documents. If there is a requirement to adjust the frames during the add process to make them all equal, perform the following steps:
- Create a new blank frame with the desired options or copy the source frame with the output options specified using the create_frame_from method.
- Resize the source frame/image to the desired dimensions using the Resize method.
- Add the source frame/image pixels to the new frame.
- Add the new frame to the output TIFF image.
Export Multi Page frames to different Image format
Sometimes you need to export Multi-page TIFF frames to some other image file format. This article will demonstrate how we can perform this task using Aspose.Imaging for Python via .NET API. We will use TiffImage, TiffFrame, BmpOptions and BmpImage classes to export TIFF frames to BMP image format. First, we will create instance of TIFF image and load images from local disk. Now we will iterate over TIFF frames and copy pixels of active frame using load_pixels method into Colors array and create an instance of BmpOptions for BMP image settings. Set the desired setting for BMP image creation. Create a new BMP image using BmpOptions object and save BMP image using frame pixels, copied in Colors array.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.bmp import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.imageoptions import * | |
from aspose.imaging.sources import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with aspycore.as_of(Image.load(file_name), TiffImage) as multi_image: | |
# Create an instance of int to keep track of frames in TiffImage | |
frame_counter = 0 | |
# Iterate over the TiffFrames in TiffImage | |
for tiff_frame in multi_image.frames: | |
multi_image.active_frame = tiff_frame | |
# Load Pixels of TiffFrame into an array of Colors | |
pixels = multi_image.load_pixels(tiff_frame.bounds) | |
# Create an instance of bmpCreateOptions | |
with BmpOptions() as bmp_create_options: | |
bmp_create_options.bits_per_pixel = 24 | |
out_path = os.path.join(data_dir, f"ConcatExtractTIFFFramesToBMP_out{frame_counter}.bmp") | |
# Set the Source of bmpCreateOptions as FileCreateSource by specifying the location where output will be saved | |
bmp_create_options.source = FileCreateSource(out_path, False) | |
# Create a new bmpImage | |
with aspycore.as_of(Image.create(bmp_create_options, tiff_frame.width, tiff_frame.height), BmpImage) as bmp_image: | |
# Save the bmpImage with pixels from TiffFrame | |
bmp_image.save_pixels(tiff_frame.bounds, pixels) | |
bmp_image.save() | |
if delete_output: | |
os.remove(out_path) | |
frame_counter += 1 |
Please note, the above provided code snippet requires setting the valid license for Aspose.Imaging for Python via .NET API. This is because Aspose.Imaging APIs restrict the usage of core features such as load_pixels & save_pixels in evaluation mode. Please check the details for Evaluation Version Limitations_imaging.net.
Adding Multiple images inside Tiff Frames
This article will demonstrate how we can we add multiple images inside single tiff using Aspose.Imaging for Python via .NET API. We will use TiffImage, TiffFrame, classes to add multiple images inside tiff frames. Below provided code snippet demonstrates this concept.
import aspose.pycore as aspycore | |
from aspose.imaging import Image, ResizeType, RasterImage | |
from aspose.imaging.fileformats.tiff import TiffImage, TiffFrame | |
from aspose.imaging.fileformats.tiff.enums import TiffExpectedFormat | |
from aspose.imaging.imageoptions import TiffOptions | |
from aspose.imaging.sources import StreamSource | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
with Image.load(os.path.join(data_dir, "template.png")) as temp_image: | |
width = temp_image.width | |
height = temp_image.height | |
tiff_options = TiffOptions(TiffExpectedFormat.DEFAULT) | |
tiff_options.source = StreamSource() | |
# create a new tiff image | |
with aspycore.as_of(Image.create(tiff_options, width, height), TiffImage) \ | |
as tiff_image: | |
# do some image processing | |
files = [file for file in os.listdir(data_dir) if file.endswith((".jpg", ".jpeg"))] | |
index = 0 | |
for file in files: | |
with Image.load(os.path.join(data_dir, file)) as input_image: | |
input_image.resize(width, height, ResizeType.NEAREST_NEIGHBOUR_RESAMPLE) | |
if index > 0: | |
newframe = TiffFrame(tiff_options, width, height) | |
tiff_image.add_frame(newframe) | |
frame = tiff_image.frames[index] | |
frame.save_pixels(frame.bounds, (aspycore.as_of(input_image, RasterImage)).load_pixels(input_image.bounds)) | |
index += 1 | |
# save all changes | |
file_name = os.path.join(data_dir, "output.tiff") | |
tiff_image.save(file_name) | |
if delete_output: | |
os.remove(file_name) |
Concatenate Multiple TIFF Images
Sometimes you need to concatenate a TIFF Image into another TIFF image to meet an application need. Aspose.Imaging APIs support the feature of concatenating multiple Tiff images, whereas this article exhibits the TIFF image concatenation feature of Aspose.Imaging for Python via .NET API. We will use TiffImage and TiffFrame classes to concatenate multiple TIFF images. We can use both standard methods, from file and from stream, to concatenate TIFF images.
Images Having Single Frame
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffFrame, TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffImage and load the copied destination image | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
# Create an instance of TiffImage and load the source image | |
with aspycore.as_of(Image.load(os.path.join(data_dir, "couple.tif")), TiffImage) as image1: | |
# Create an instance of TIffFrame and copy active frame of source image, Add copied frame to destination image and Save the image with changes. | |
frame = TiffFrame.copy_frame(image1.active_frame) | |
image.add_frame(frame) | |
image.save(os.path.join(data_dir, "ConcatTIFFImages_out.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "ConcatTIFFImages_out.tiff")) |
Concatenating Images from Disk
Firstly, we will create instances of images and load images from the local disk, then we will copy the active frame of source image using copy_frame method of TiffFrame class and add that copied frame to destination image with the help of add_frame method of TiffImage class. Finally we will save image back to local disk.
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffFrame, TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffImage and load the copied destination image | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
# Create an instance of TiffImage and load the source image | |
with aspycore.as_of(Image.load(os.path.join(data_dir, "couple.tif")), TiffImage) as image1: | |
# Create an instance of TIffFrame and copy active frame of source image, Add copied frame to destination image and Save the image with changes. | |
frame = TiffFrame.copy_frame(image1.active_frame) | |
image.add_frame(frame) | |
image.save(os.path.join(data_dir, "ConcatTIFFImages_out.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "ConcatTIFFImages_out.tiff")) |
Concatenating Images from Stream
Sometimes the images that we need to process are stored as a stream. In that case, use the overloaded version of the load method. Remaining logic would be remained same as described above.
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffFrame, TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffImage and load the copied destination image | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
# Create an instance of TiffImage and load the source image | |
with aspycore.as_of(Image.load(os.path.join(data_dir, "couple.tif")), TiffImage) as image1: | |
# Create an instance of TIffFrame and copy active frame of source image, Add copied frame to destination image and Save the image with changes. | |
frame = TiffFrame.copy_frame(image1.active_frame) | |
image.add_frame(frame) | |
image.save(os.path.join(data_dir, "ConcatTIFFImages_out.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "ConcatTIFFImages_out.tiff")) |
Images Having Several Frames
Below provided sample demonstrates the usage of Aspose.Imaging for Python via .NET API to concatenate Tiff images that could have several frames. For demonstration purposes, we will read a list of Tiff images, and create a new Tiff image that will hold the frames from all read Tiff images.
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import TiffOptions | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
files = [os.path.join(data_dir, "template.tiff"), os.path.join(data_dir, "template.tiff")] | |
create_options = TiffOptions(TiffExpectedFormat.DEFAULT) | |
create_options.bits_per_sample = [1] | |
create_options.orientation = TiffOrientations.TOP_LEFT | |
create_options.photometric = TiffPhotometrics.MIN_IS_BLACK | |
create_options.compression = TiffCompressions.CCITT_FAX3 | |
create_options.fill_order = TiffFillOrders.LSB_2_MSB | |
# Create a new image by passing the TiffOptions and size of first frame, we will remove the first frame at the end, cause it will be empty | |
output = None | |
images = [] | |
for file in files: | |
# Create an instance of TiffImage and load the source image | |
input_ = aspycore.as_of(Image.load(file), TiffImage) | |
images.append(input_) | |
for frame in input_.frames: | |
if output is None: | |
# Create a new tiff image with first frame defined. | |
output = TiffImage(TiffFrame.copy_frame(frame)) | |
else: | |
# Add copied frame to destination image | |
output.add_frame(TiffFrame.copy_frame(frame)) | |
if output is not None: | |
# Save the result | |
output.save(os.path.join(data_dir, "ConcatenateTiffImagesHavingSeveralFrames_out.tif"), create_options) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "ConcatenateTiffImagesHavingSeveralFrames_out.tif")) | |
# dispose all images | |
for image in images: | |
with image as _: | |
pass |
Data Recovery Options
Sometimes you may encounter a TIFF image that cannot be rendered properly while using traditional image viewers such as Windows Photo Viewer because the image is damaged or corrupted. When loaded with Aspose.Imaging, such images may throw exceptions and you may not be able to process them further. Aspose.Imaging 2.2.0 and later supports data recovery mode for TIFF files. The data recovery allows you to load a TIFF file that has improper data layout or corrupted data strips. Data recovery replaces the corrupted data with any color specified, and you can retrieve the rest of the data for further processing without experiencing any exception. This mechanism is especially useful for Tiff file format since it stores the data in strips. When a strip is damaged the other strips may still retain the correct information.
Aspose.Imaging provides two recovery modes which provide different results.
- CONSISTENT_RECOVER: The consistent recovery mode tries to recover all data as long as corruption does not break the file format and allows further processing.
- MAXIMAL_RECOVER: The maximal recovery mode recovers all data even if the file format has a corrupted structure and further processing may yield unexpected effects.
Below is sample code that shows how to use the two data recovery modes.
import aspose.pycore as aspycore | |
from aspose.imaging import Image, LoadOptions, DataRecoveryMode, Color | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of LoadOptions and set LoadOptions properties | |
load_options = LoadOptions() | |
load_options.data_recovery_mode = DataRecoveryMode.CONSISTENT_RECOVER | |
load_options.data_background_color = Color.red | |
# Create an instance of Image and load a damaged image by passing the instance of LoadOptions | |
with Image.load(file_name, load_options) as image: | |
pass |
When a damaged or corrupted TIFF file is loaded or saved without using data recovery you may get an exception.
TiffOptions Configuration
Developers can adjust different properties of TiffOptions class to get desired results. In this document, we will focus on 4 main properties that controls the resultant image attributes.
These properties are listed below.
Whenever we initialize an empty TiffOptions structure, each option is set to its default value, for instance compression is set to None, bits_per_sample is set as 1 and photometric as MIN_IS_WHITE. Saving into this format will make the final image black n white and this is expected behavior for such options combination. In order to get the colored results you have to set all the above mentioned properties to values that correspond to desired color space or you can initialize the TiffOptions structure with predefined settings as discussed later in this article. Provided below is a table describing the expected parameter values that you can set in order to achieve desired results. Please note, you should set all 4 columns through TiffOptions in order to save any loaded/created image to TIFF file format.
TiffOptions.photometric |
TiffOptions.compression | TiffOptions.bits_per_sample | TiffOptions.predictor |
---|---|---|---|
Palette | LZW/Uncompressed | 1/4/8/16 (palette, color mode) single channel only | None |
MinIsWhite/MinIsBlack | LZW/Uncompressed | 1/4/8/16 (gray-scale mode) single channel only | None |
Palette | LZW/Uncompressed | 8 (palette, color mode) single channel only | Horizontal (more compression achieved for LZW same patterns) |
MinIsWhite/MinIsBlack | LZW/Uncompressed | 8 (gray-scale mode) single channel only | Horizontal (more compression achieved for LZW same patterns) |
RGB | LZW/Uncompressed | [8,8,8] (3 RGB channels) | None/Horizontal |
RGB | LZW/Uncompressed | [8,8,8,8] (3 RGB channels and additional alpha channel may be set through TiffOptions.AlphaStorage) Actually any additional channels count is supported but each channel must have 8 bit size like [8,8,8,8,8,8] | None/Horizontal |
All 4 properties should be set through TiffOptions in order to save any image format to Tiff format. When employing different combinations, some viewers (including the Windows Photo Viewer) may refuse to render the resultant image due to the limited support they offer. In such case, please pick different viewer for your testing.
Predefined Settings for TiffOptions Class
In order to facilitate the users and to avoid the miss-configuration of the TiffOptions instance, the Aspose.Imaging for Python via .NET API has exposed another constructor that accepts a parameter of type TiffExpectedFormat. Based on the selected value from the TiffExpectedFormat enumeration, the API auto configures all the mandatory properties for the TiffOptions instance in order to produce the desired results. Before we move towards the sample code, here is the list of the TiffExpectedFormat fields and their details for better understanding of the usage.
- TiffExpectedFormat.Default: Setting the field to Default acts similar to the default constructor of TiffOptions class with no compression set and BitsPerPixel set to 1 in order to produce a black n white result. It is advised to use this field when other format specific properties are to be set manually according to the desired results.
- TiffExpectedFormat.TiffCcitRle: Specific to RLE encoding while saving the result in 1 BitsPerPixel (black n white) TIFF format.
- TiffExpectedFormat.TiffCcittFax3: Specific to CCITT Fax3 encoding while saving the result in 1 BitsPerPixel (black n white) TIFF format.
- TiffExpectedFormat.TiffCcittFax4: Specific to CCITT Fax4 encoding while saving the result in 1 BitsPerPixel (black n white) TIFF format.
- TiffExpectedFormat.TiffDeflateBW: Specific to Deflate compression while saving the result in 1 BitsPerPixel (black n white) TIFF format.
- TiffExpectedFormat.TiffDeflateRGB: Specific to Deflate compression while saving the result in RGB (color) TIFF format.
- TiffExpectedFormat.TiffJpegRGB: Specific to Jpeg compression while saving the result in RGB (color) TIFF format.
- TiffExpectedFormat.TiffJpegYCBCR: Specific to Deflate compression while saving the result in YCBCR (color) TIFF format.
- TiffExpectedFormat.TiffLzwBW: Specific to LZW compression while saving the result in 1 BitsPerPixel (black n white) TIFF format.
- TiffExpectedFormat.TiffLzwRGB: Specific to LZW compression while saving the result in RGB (color) TIFF format.
- TiffExpectedFormat.TiffLzwRGBA: Specific to LZW compression while saving the result in RGBA (color with transparency) TIFF format.
- TiffExpectedFormat.TiffNoCompressionBW: Specific to uncompressed TIFF format while saving the result in 1 BitsPerPixel (black n white).
- TiffExpectedFormat.TiffNoCompressionRGB: Specific to uncompressed TIFF format while saving the result in RGB (color).
- TiffExpectedFormat.TiffNoCompressionRGBA: Specific to uncompressed TIFF format while saving the result in RGBA (color with transparency).
The following code snippet elaborates the usage of TiffExpectedFormat fields while creating an instance of TiffOptions class.
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff.enums import TiffExpectedFormat | |
from aspose.imaging.imageoptions import TiffOptions | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Load an image through file path location or stream | |
with Image.load(file_name) as image: | |
# Create an instance of TiffOptions while specifying desired format | |
# Passing TiffExpectedFormat.TIFF_JPEG_RGB will set the compression to Jpeg and BitsPerPixel according to the RGB color space. | |
options = TiffOptions(TiffExpectedFormat.TIFF_JPEG_RGB) | |
image.save(os.path.join(data_dir, "output.tiff"), options) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "output.tiff")) |
Support for Deflate and Adobe Deflate Compression
The TIFF (Tagged Image File Format) file format supports various types of compression whereas the compression type is stored as a tag (an integer value) in the file. One of such compression methods is Adobe Deflate (previously known as Deflate). Since the release of Aspose.Imaging 2.6.0, the API supports this compression method for loading, converting & creating TIFF images.
Loading Image
Aspose.Imaging for Python via .NET API hides all the ugly details from the user and provides an easy to use mechanism to load images for further processing. In order to load a TIFF image having Adobe Deflate compression, user has to pass the file path location or stream object to the Image.Load method and cast the object to TiffImage as per requirement.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffOptions and set its various properties | |
options = TiffOptions(TiffExpectedFormat.DEFAULT) | |
options.bits_per_sample = [8, 8, 8] | |
options.photometric = TiffPhotometrics.RGB | |
options.xresolution = TiffRational(72) | |
options.yresolution = TiffRational(72) | |
options.resolution_unit = TiffResolutionUnits.INCH | |
options.planar_configuration = TiffPlanarConfigs.CONTIGUOUS | |
# Set the Compression to AdobeDeflate | |
options.compression = TiffCompressions.ADOBE_DEFLATE | |
# Or Deflate | |
# Options.Compression = TiffCompressions.Deflate; | |
# Load an existing image in an instance of RasterImage | |
with aspycore.as_of(Image.load(file_name), RasterImage) as image: | |
# Create a new TiffImage from the RasterImage and Save the resultant image while passing the instance of TiffOptions | |
with TiffImage(TiffFrame(image)) as tiff_image: | |
tiff_image.save(os.path.join(data_dir, "output.tiff"), options) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "output.tiff")) |
Support Tiff deflate Images with Alpha
Aspose.Imaging for Python via .NET API hides all the ugly details from the user and provides an easy to use mechanism to load images for further processing. In order to load a TIFF image and save that with Deflate compression with Alpha, user has to pass the file path location or stream object to the Image.Load method and cast the object to TiffImage as per requirement.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffOptions and set its various properties | |
options = TiffOptions(TiffExpectedFormat.DEFAULT) | |
options.bits_per_sample = [8, 8, 8] | |
options.photometric = TiffPhotometrics.RGB | |
options.xresolution = TiffRational(72) | |
options.yresolution = TiffRational(72) | |
options.resolution_unit = TiffResolutionUnits.INCH | |
options.planar_configuration = TiffPlanarConfigs.CONTIGUOUS | |
# Set the Compression to AdobeDeflate | |
options.compression = TiffCompressions.ADOBE_DEFLATE | |
# Or Deflate | |
# Options.Compression = TiffCompressions.Deflate; | |
# Load an existing image in an instance of RasterImage | |
with aspycore.as_of(Image.load(file_name), RasterImage) as image: | |
# Create a new TiffImage from the RasterImage and Save the resultant image while passing the instance of TiffOptions | |
with TiffImage(TiffFrame(image)) as tiff_image: | |
tiff_image.save(os.path.join(data_dir, "output.tiff"), options) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "output.tiff")) |
Saving Image
Converting any raster image to TIFF with Deflate/Adobe Deflate compression is easy as follow.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffOptions and set its various properties | |
options = TiffOptions(TiffExpectedFormat.DEFAULT) | |
options.bits_per_sample = [8, 8, 8] | |
options.photometric = TiffPhotometrics.RGB | |
options.xresolution = TiffRational(72) | |
options.yresolution = TiffRational(72) | |
options.resolution_unit = TiffResolutionUnits.INCH | |
options.planar_configuration = TiffPlanarConfigs.CONTIGUOUS | |
# Set the Compression to AdobeDeflate | |
options.compression = TiffCompressions.ADOBE_DEFLATE | |
# Or Deflate | |
# Options.Compression = TiffCompressions.Deflate; | |
# Load an existing image in an instance of RasterImage | |
with aspycore.as_of(Image.load(file_name), RasterImage) as image: | |
# Create a new TiffImage from the RasterImage and Save the resultant image while passing the instance of TiffOptions | |
with TiffImage(TiffFrame(image)) as tiff_image: | |
tiff_image.save(os.path.join(data_dir, "output.tiff"), options) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "output.tiff")) |
Creating Image
Below provided sample demonstrates the usage of Aspose.Imaging for Python via .NET API to create an image from scrach using the Adobe Deflate compression method.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.tiff import TiffImage, TiffFrame, TiffRational | |
from aspose.imaging.fileformats.tiff.enums import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
# Create an instance of TiffOptions and set its various properties | |
options = TiffOptions(TiffExpectedFormat.DEFAULT) | |
options.bits_per_sample = [8, 8, 8] | |
options.photometric = TiffPhotometrics.RGB | |
options.xresolution = TiffRational(72) | |
options.yresolution = TiffRational(72) | |
options.resolution_unit = TiffResolutionUnits.INCH | |
options.planar_configuration = TiffPlanarConfigs.CONTIGUOUS | |
# Set the Compression to AdobeDeflate | |
options.compression = TiffCompressions.ADOBE_DEFLATE | |
# Or Deflate | |
# options.compression = TiffCompressions.DEFLATE; | |
# Create a new TiffImage with specific size and TiffOptions settings | |
with TiffImage(TiffFrame(options, 100, 100)) as tiff_image: | |
# Loop over the pixels to set the color to red | |
red = Color.red | |
active_frame = tiff_image.active_frame | |
for i in range(100): | |
active_frame.set_pixel(i, i, red) | |
# Save resultant image | |
tiff_image.save(os.path.join(data_dir, "result.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.tiff")) |
Compressing TIFF Images
Aspose.Imaging for Python via .NET API can be used to convert other raster formats to TIFF image format and even change the compression of existing TIFF image. The API can also be used to store different images as frames in a TIFF image for archiving purposes while compressing the images to lowest data size. The image compression in any case should be performed by reducing the source data size regardless of the compression algorithm used. In order to achieve the best compression ratio we may use indexed color spaces. The below provided code snippet performs the best compression using 16 indexed colors only and LZW compression algorithm however the source colors are slightly dithered.
import aspose.pycore as aspycore | |
from aspose.imaging import Image, ColorPaletteHelper | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import TiffOptions | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Load an image through file path location or stream | |
with Image.load(file_name) as image: | |
# Create an instance of TiffOptions for the resultant image | |
output_settings = TiffOptions(TiffExpectedFormat.DEFAULT) | |
# Set bits_per_sample, compression, photometric mode and grayscale palette | |
output_settings.bits_per_sample = [4] | |
output_settings.compression = TiffCompressions.LZW | |
output_settings.photometric = TiffPhotometrics.PALETTE | |
output_settings.palette = ColorPaletteHelper.create_4_bit_grayscale(False) | |
image.save(os.path.join(data_dir, "result.tiff"), output_settings) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.tiff")) |
Another approach which can be used since the release of Aspose.Imaging v2.6.0 is by using the Adobe Deflate compression as demonstrated below.
import aspose.pycore as aspycore | |
from aspose.imaging import Image, ColorPaletteHelper | |
from aspose.imaging.fileformats.tiff.enums import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Load an image through file path location or stream | |
with Image.load(file_name) as image: | |
# Create an instance of TiffOptions for the resultant image | |
output_settings = TiffOptions(TiffExpectedFormat.DEFAULT) | |
# Set bits_per_sample, photometric mode & compression mode | |
output_settings.bits_per_sample = [4] | |
output_settings.compression = TiffCompressions.ADOBE_DEFLATE | |
output_settings.photometric = TiffPhotometrics.PALETTE | |
# Set grayscale palette | |
output_settings.palette = ColorPaletteHelper.create_4_bit_grayscale(False) | |
image.save(os.path.join(data_dir, "result.tiff"), output_settings) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.tiff")) |
Splitting TIFF Frames
A Tiff image can have multiple frames and a requirement may arise to split these frames into several images. This article demonstrates the use of Aspose.Imaging for Python via .NET API to achieve this requirement in an efficient manner with a few lines of code.
Saving Each Frame in TIFF Format
Splitting the Tiff frames is easy and can be achieved in below simple steps.
- Firstly, create an instance of TiffImage and load a Tiff file from the disk/stream.
- Iterate over the Tiff frame collection.
- Save each frame to disc in Tiff format.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffImage and load the file from disc | |
with aspycore.as_of(Image.load(file_name), TiffImage) as multi_image: | |
# Initialize a variable to keep track of the frames in the image, Iterate over the tiff frame collection and Save the image | |
i = 0 | |
for tiff_frame in multi_image.frames: | |
tiff_frame.save(os.path.join(data_dir, f"{i}_out.tiff"), TiffOptions(TiffExpectedFormat.TIFF_JPEG_RGB)) | |
if delete_output: | |
os.remove(os.path.join(data_dir, f"{i}_out.tiff")) | |
i += 1 |
Saving Each Frame in Other Format
Most of the process is the same as discussed above with a minor change, that is; while saving the frame to disc, you may pass an object of the ImageOptionBase according to the desired raster image format. Below provided code snippet demonstrates this concept by saving each frame in PNG format.
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
from aspose.imaging.imageoptions import PngOptions | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Create an instance of TiffImage and load the file from disc | |
with aspycore.as_of(Image.load(file_name), TiffImage) as multi_image: | |
# Initialize a variable to keep track of the frames in the image, Iterate over the tiff frame collection and Save the image | |
i = 0 | |
for tiff_frame in multi_image.frames: | |
out_file_name = os.path.join(data_dir, f"{i}_out.png") | |
tiff_frame.save(out_file_name, PngOptions()) | |
if delete_output: | |
os.remove(out_file_name) | |
i += 1 |
Memory strategy optimization
Loading of Tiff images can be proceeded using memory strategy optimization - i.e. limiting memory buffer size for operation.
import aspose.pycore as aspycore | |
from aspose.imaging import * | |
from aspose.imaging.fileformats.bmp import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.imageoptions import * | |
from aspose.imaging.sources import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
# Setting a memory limit of 10 megabytes for target loaded image | |
obj_init = LoadOptions() | |
obj_init.buffer_size_hint = 10 | |
with Image.load(file_name, obj_init) as image: | |
image.save(os.path.join(data_dir, "output.tiff"), TiffOptions(TiffExpectedFormat.DEFAULT)) | |
obj_init2 = LoadOptions() | |
obj_init2.buffer_size_hint = 10 | |
with Image.load(file_name, obj_init2) as image: | |
image.save(os.path.join(data_dir, "output.tiff"), TiffOptions(TiffExpectedFormat.TIFF_CCIT_RLE)) | |
obj_init3 = LoadOptions() | |
obj_init3.buffer_size_hint = 10 | |
with Image.load(file_name, obj_init3) as image: | |
image.save(os.path.join(data_dir, "output.tiff"), TiffOptions(TiffExpectedFormat.TIFF_DEFLATE_RGB)) | |
obj_init4 = LoadOptions() | |
obj_init4.buffer_size_hint = 10 | |
with Image.load(file_name, obj_init4) as image: | |
image.save(os.path.join(data_dir, "output.tiff"), TiffOptions(TiffExpectedFormat.TIFF_JPEG_Y_CB_CR)) | |
obj_init5 = LoadOptions() | |
obj_init5.buffer_size_hint = 10 | |
with Image.load(file_name, obj_init5) as image: | |
image.save(os.path.join(data_dir, "output.tiff"), TiffOptions(TiffExpectedFormat.TIFF_LZW_CMYK)) | |
obj_init6 = LoadOptions() | |
obj_init6.buffer_size_hint = 10 | |
with Image.load(file_name, obj_init6) as image: | |
image.save(os.path.join(data_dir, "output.tiff"), TiffOptions(TiffExpectedFormat.TIFF_NO_COMPRESSION_RGB)) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "output.tiff")) |
Get tiff original options from image
Aspose.Imaging API allows to save tiff images in original format keeping all original settings.
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with Image.load(file_name) as image: | |
output1 = "result1.tiff" | |
output2 = "result2.tiff" | |
image.save(os.path.join(data_dir, output1), image.get_original_options()) | |
frame = (aspycore.as_of(image, TiffImage)).frames[0] | |
frame.save(os.path.join(data_dir, output2), frame.get_original_options()) | |
if delete_output: | |
os.remove(os.path.join(data_dir, output1)) | |
os.remove(os.path.join(data_dir, output2)) |
Export tiff to pdf (set dpi for exported pdf)
Aspose.Imaging library supports possibility to convert image to pdf and specify DPI for exported pdf
import aspose.pycore as aspycore | |
from aspose.imaging import Image, ResolutionSetting | |
from aspose.imaging.fileformats.tiff import TiffImage | |
from aspose.imaging.imageoptions import PdfOptions | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with Image.load(file_name) as image: | |
tiff_image = aspycore.as_of(image, TiffImage) | |
pdf_options = PdfOptions() | |
pdf_options.resolution_settings = ResolutionSetting(tiff_image.horizontal_resolution, tiff_image.vertical_resolution) | |
image.save(os.path.join(data_dir, "result.pdf"), pdf_options) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.pdf")) |
Support for extracting paths from TIFF
Clipping Path
Clipping path is the Photoshop technique to remove the background from an image. Photoshop allows you to select a part of an image using Clipping Path and save the path within a file. Clipping Paths allow you to hide the part of an image you don’t want to appear. Anything inside the clipping path will be visible, but anything outside of it will be transparent.
Other words Photoshop makes it possible to isolate certain parts of an image, without permanently changing the layer. This allows you to tweak the image at any point in the creative process. Clipping Paths are a traditional method of cutting out objects or people in Photoshop that allows you to create image files with transparent backgrounds. This approach works best with objects or people with “hard” edges around the object or person you want to cut out.
Access Clipping Paths in TIFF image
PathResources property allows you to access Clipping Paths in TIFF frame. The following code retrieves paths from TIFF image and displays their names in the console:
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
for path in image.active_frame.path_resources: | |
print(path.name) |
Modify existing Clipping Paths
You can easily modify already existing Clipping Paths. For instance, you can keep only one Clipping Path in the image:
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
paths = image.active_frame.path_resources | |
if paths is not None and paths.length > 0: | |
image.active_frame.path_resources = [paths[0]] |
Create Clipping Path manually
You can manually create Clipping Path in TIFF image. In order to do that you need to create an instance of PathResource class. The following code demonstrates the way how you can create an empty path in TIFF image:
import aspose.pycore as aspycore | |
from aspose.imaging import Image, PointF | |
from aspose.imaging.fileformats.core.vectorpaths import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.fileformats.tiff.pathresources import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
file_name = os.path.join(data_dir, "template.tiff") | |
def create_records(coordinates): | |
records = create_bezier_records(coordinates) | |
rec = LengthRecord() | |
rec.is_open = False | |
rec.record_count = len(records) | |
records.insert(0, rec) | |
return records | |
def create_bezier_records(coordinates): | |
return [create_bezier_record(pt) \ | |
for pt in coordinates_to_points(coordinates)] | |
def coordinates_to_points(coordinates): | |
for index in range(len(coordinates), 2): | |
yield PointF(coordinates[index], coordinates[index + 1]) | |
def create_bezier_record(point): | |
ret = BezierKnotRecord() | |
ret.path_points = [point, point, point] | |
return ret | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
prec = PathResource() | |
prec.block_id = 2000 | |
prec.name = "My Clipping Path" | |
prec.records = create_records([0.2, 0.2, 0.8, 0.2, 0.8, 0.8, 0.2, 0.8]) | |
image.active_frame.path_resources = [prec] | |
image.save(os.path.join(data_dir, "result.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.tiff")) |
Get existing Clipping Path
The following code shows how to get existing Clipping Path from TIFF image:
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
# Get path resources from TIFF image | |
path_resources = image.active_frame.path_resources | |
if path_resources is not None: | |
for path in path_resources: | |
if path.block_id == 2999: | |
# Determine clipping path name | |
clipping_path_name = path.name | |
# Get clipping path | |
clipping_path = path | |
# Write record count to the console | |
print("Clipping path record count: ", len(clipping_path.records)) |
Change Clipping Path
In case if you have multiple paths in TIFF image you can easily change which of them is Clipping Path:
import aspose.pycore as aspycore | |
from aspose.imaging import Image | |
from aspose.imaging.fileformats.tiff import TiffImage | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
# Get path resources from TIFF image | |
path_resources = image.active_frame.path_resources | |
if path_resources is not None: | |
for path in path_resources: | |
if path.block_id == 2999: | |
# Determine clipping path name | |
clipping_path_name = path.name | |
# Get clipping path | |
clipping_path = path | |
clipping_path.name = "Test" | |
# Save changed image | |
image.save(os.path.join(data_dir, "result.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.tiff")) |
Create Clipping Path from scratch
The following source code sample demonstrates how to create paths in TIFF image from scratch:
import aspose.pycore as aspycore | |
from aspose.imaging import Image, PointF | |
from aspose.imaging.fileformats.core.vectorpaths import * | |
from aspose.imaging.fileformats.tiff import * | |
from aspose.imaging.fileformats.tiff.enums import * | |
from aspose.imaging.fileformats.tiff.pathresources import * | |
import os | |
if 'TEMPLATE_DIR' in os.environ: | |
templates_folder = os.environ['TEMPLATE_DIR'] | |
else: | |
templates_folder = r"C:\Users\USER\Downloads\templates" | |
delete_output = 'SAVE_OUTPUT' not in os.environ | |
data_dir = templates_folder | |
file_name = os.path.join(data_dir, "template.tiff") | |
def create_records(coordinates): | |
records = create_bezier_records(coordinates) | |
obj_init4 = LengthRecord() | |
obj_init4.is_open = False | |
obj_init4.record_count = len(records) | |
records.insert(0, obj_init4) | |
return records | |
def create_bezier_records(coordinates): | |
return [create_bezier_record(pt) \ | |
for pt in coordinates_to_points(coordinates)] | |
def coordinates_to_points(coordinates): | |
for index in range(0, len(coordinates), 2): | |
yield PointF(coordinates[index], coordinates[index + 1]) | |
def create_bezier_record(point): | |
ret = BezierKnotRecord() | |
ret.path_points = [point, point, point] | |
return ret | |
with aspycore.as_of(Image.load(file_name), TiffImage) as image: | |
path1 = PathResource() | |
path1.block_id = 2000 | |
path1.name = "My Clipping Path" | |
path1.records = create_records([0.2, 0.2, 0.8, 0.2, 0.8, 0.8, 0.2, 0.8]) | |
path2 = PathResource() | |
path2.block_id = 2999 | |
path2.name = "My Clipping Path" | |
path2.records = [] | |
image.active_frame.path_resources = [path1, path2] | |
image.save(os.path.join(data_dir, "result.tiff")) | |
if delete_output: | |
os.remove(os.path.join(data_dir, "result.tiff")) |
Clipping Path content
To create your own Clipping Paths you need to understand their content. Photoshop stores its paths as resources with IDs in the range 2000 through 2997. The name of the resource is the name given to the path when it was saved. If the file contains a resource with an ID of 2999, then this resource contains the name of the clipping path. Each path has a set of records to hold the data.
Record classes: LengthRecord - contains the number of Bezier knot records. BezierKnotRecord - describes the knots of the path. ClipboardRecord - contains four fixed-point numbers for the bounding rectangle.
More details you can find in Adobe Photoshop File Formats Specification.