SixLabors / ImageSharp

:camera: A modern, cross-platform, 2D Graphics library for .NET
https://sixlabors.com/products/imagesharp/
Other
7.45k stars 853 forks source link

created/overwritten/copied TIFF images are invalid for Adobe Premiere Pro #2297

Closed MaciejSzulborski closed 1 year ago

MaciejSzulborski commented 2 years ago

Prerequisites

ImageSharp version

2.1.3

Other ImageSharp packages and versions

SixLabors.ImageSharp 2.1.3, SixLabors.ImageSharp.Drawing 1.0.0-beta14, SixLabors.Fonts 1.0.0-beta17

Environment (Operating system, version and so on)

Windows Server 2019 Standard 1809

.NET Framework version

.Net 6.0, .Net Framework 4.8

Description

Tiff files created by ImageSharp are not recognized by Adobe Premiere Pro on any try of import. If you try to import a tiff file an error will pop up: "The file cannot be opened because of a header error" If you take a tiff file created by ImageSharp, open it with Paint or Adobe Photoshop and save it without any changes, choosing TIFF format, Importing files to Premiere Pro becomes possible. It seems there is an issue, when encoding the tiff image by ImageSharp since other software can save the image in format properly. I could not find any differences in metadata that would indicate which parameter is invalid.

Steps to Reproduce

using Image<Rgba32> image = new(1920, 1080); using MemoryStream stream = new(); image.SaveAsTiff(output);

Images

Premiere Pro error

brianpopow commented 2 years ago

What is the memory stream used for in your repro? Seems unnecessary.

The following should be enough:

using Image<Rgba32> image = new(1920, 1080);
image.SaveAsTiff("output.tiff");

I kind of doubt that there is an issue with "the file header" of ImageSharp tiff's. tiffinfo from libtiff does not report any errors. ImageMagick with imagemagick identify -verbose does not report any error.

Also I can open ImageSharp Tiff images with any viewer I have:

None of those complains. I do not have access to Adobe Premiere Pro.

MaciejSzulborski commented 1 year ago

Hi,

Thank you for a prompt reply.

The memory stream was my bad, I forgot to delete it after simplifying my example.

I have to agree with you about the header, I took the stream of the file to decode the header into hexdec string, and read about tiff format headers. It all seems fine. I also read on various blogs that Premiere Pro "header error" is an unhandled exception for any issues when importing files. I have spent several hours with their support trying to get them to tell me what exactly makes the file crash but no luck, "file is no good" is the best I got out of them.

I conducted multiple tests, creating files in all possible ways using ImageSharp. I don't have this problem with png or jpeg.

I created a file in Photoshop to ensure that it works fine in Premiere pro, it's the same FullHD Black background (valid.tif attached). I thought if I load it via ImageSharp and just Save a copy of it without any changes (Copy.tif attached), the file should be identical, therefore be acceptable for Premiere Pro.

using Image image = Image.Load(fileToCopy, out IImageFormat format);

using MemoryStream stream = new();

image.SaveAsTiff(stream);

File.WriteAllBytes(outputPath, stream.ToArray());

The output Copy.tiff file throws the same error when importing with PremierePro. Again, if I open it in Photoshop or Paint, save as Tiff, it will work just fine.

I tried comparing 2 files, MediaInfo shows identical metadata, and the decoded header indicates Tiff properly. The only thing out of order is different file sizes. If I copy the files using File Explorer, the created copy has the same file size. From those two facts I presume there must be some differences between those files, and whatever it is it causes Premiere to crash. Attachments.zip

brianpopow commented 1 year ago

Maybe try a 1x1 pixel image. Save a 1x1 black pixel image with ImageSharp and again with another program you know is working with PremierePro. Then compare those binary and see what the difference is.

Maybe it's as simple as the file extension is not as expected? Tiff instead of Tif? A quick google search shows that this indeed can cause this issue.

Other then that, I am not sure what we can do about it. If libtiff does not complain, I am pretty sure the tiff is valid.

I really think the PremierePro supports needs to tell why this error is happening.

MaciejSzulborski commented 1 year ago

I created 2 1px files: -1pxPaint.tif -1pxImageSharp.tif

1pxImageSharp was created like so:

using Image<Rgba32> image = new(1, 1);
TiffEncoder tiffEncoder = new()
{
    BitsPerPixel = TiffBitsPerPixel.Bit24,
    PhotometricInterpretation = SixLabors.ImageSharp.Formats.Tiff.Constants.TiffPhotometricInterpretation.Rgb,
    Compression = SixLabors.ImageSharp.Formats.Tiff.Constants.TiffCompression.Lzw
};
image.SaveAsTiff(@"\\plpns01\pl-sdi\TEMP\m_szulborski\Test\DubcardGenerator\1pxImageSharp.tif", tiffEncoder);

Encoder was needed because Paint creates Tiff with LZW Compression by default, and I wanted files to be identical.

Comparing 2 files I can see:

1pxPaint: 49492A000E0000008000205010000F00FE00040001000000000000000001040001000000010000000101040001000000010000000201030003000000C80000000301030001000000050000000601030001000000020000001101040001000000080000001501030001000000030000001601040001000000010000001701040001000000050000001A01050001000000CE0000001B01050001000000D60000001C01030001000000010000002801030001000000020000003D01030001000000020000000000000008000800080000770100E803000000770100E8030000 1pxImageSharp: 49492A000D00000080002050100E000001040001000000010000000101040001000000010000000201030003000000BB0000000301030001000000050000000601030001000000020000001101040001000000080000001501040001000000030000001601040001000000010000001701040001000000050000001A01050001000000C10000001B01050001000000C90000001C0103000100000001000000280103000100000002000000310102000B000000D10000000000000008000800080060000000010000006000000001000000496D61676553686172700000

1pxImages.zip

brianpopow commented 1 year ago

I created 2 1px files: -1pxPaint.tif -1pxImageSharp.tif

1pxImageSharp was created like so:

paint: 4949 byteorder 2A00 magick byte
0E00 FirstIfdOffset

imagesharp: 4949 byteorder 2A00 magick byte 0D00 FirstIfdOffset

The difference is that imagesharp ifd offset starts at offset 13 and paint starts at 14. After double checking the spec, this could be indeed a violation of the spec: "The directory may be at any location in the file after the header but must begin on a word boundary."

brianpopow commented 1 year ago

@MaciejSzulborski can you try opening the following tiff with premiere pro:

1pxImageSharp.zip

I have adjusted the ifd offset there to start at the word boundary.

MaciejSzulborski commented 1 year ago

Unfortunately Premiere Pro throws the same error.

JimBobSquarePants commented 1 year ago

If the adjusted tif has exactly the same bytes as the paint one then that sounds like a bug in premier pro.

brianpopow commented 1 year ago

Unfortunately Premiere Pro throws the same error.

That's really unfortunate, I really thought this should work now. The header looks the same as from paint now:

4949 byteorder 2A00 magick byte 0E00 FirstIfdOffset

MaciejSzulborski commented 1 year ago

I have decoded .tiff file you attached and it looks like header is identical now, but there are still differences in the full byte array. 1pxPaint: 49492A000E0000008000205010000F00FE00040001000000000000000001040001000000010000000101040001000000010000000201030003000000C80000000301030001000000050000000601030001000000020000001101040001000000080000001501030001000000030000001601040001000000010000001701040001000000050000001A01050001000000CE0000001B01050001000000D60000001C01030001000000010000002801030001000000020000003D01030001000000020000000000000008000800080000770100E803000000770100E8030000 1pxImageSharp from SixLabors: 49492A000E0000008000205010000F000001040001000000010000000101040001000000010000000201030003000000C80000000301030001000000050000000601030001000000020000001101040001000000080000001501040001000000030000001601040001000000010000001701040001000000050000001A01050001000000CE0000001B01050001000000D60000001C0103000100000001000000280103000100000002000000310102000B000000DE0000003D01030001000000020000000000000008000800080060000000010000006000000001000000496D61676553686172700000

And still file size is different: 222 KB vs 224KB (it was 221KB before). I am no expert in how the files are built, but if it is supposed to be the same 1 black pixel with the same setup, shouldn't the file size and byte order be identical?

JimBobSquarePants commented 1 year ago

Ok so still differences. Thanks!

brianpopow commented 1 year ago

The header is identical, though.

@JimBobSquarePants: Is the rest of the lzw compressed data really expected to be identical? It can be a different lzw implementation and still be valid if I am not mistaken.

It would be easier to compare against uncompressed data, but I dont see any option to change that in paint.

brianpopow commented 1 year ago

Ok I have compared the lzw pixel data, it looks exactly the same:

Compressed lzw pixel data bytes: 128 0 32 80 16

The difference comes from different properties. For example ImageSharp writes the "Software" Property and set's it to "ImageSharp".

MaciejSzulborski commented 1 year ago

Ok, I see we've hit a brick wall with LZW.

Before trying out ImageSharp, I used to create .tiff images with System.Windows.Media which is unfortunately not a part of .net 6. So I went back to the old .Net Framework 4.8 and created a .tif file there. It can be imported with Premiere Pro and has 222 Bytes just like the one from Paint (with LZW).

Creating "1pxSystemWindowsMedia.tif" with .Net Framework 4.8:

using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using (FileStream stream = new FileStream(@filename, FileMode.Create))
{
    RenderTargetBitmap target = new RenderTargetBitmap(1,1,96,96, PixelFormats.Pbgra32);
    var visual = new DrawingVisual();
    using (var r = visual.RenderOpen())
    {
        SolidColorBrush brush = new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 0, 0));
        r.DrawRectangle(brush, null, new Rect(0, 0, 1, 1));
    }
    target.Render(visual);

    TiffBitmapEncoder encoder = new TiffBitmapEncoder
    {
        Compression = TiffCompressOption.None
    };
    encoder.Frames.Add(BitmapFrame.Create(target));
    encoder.Save(stream);
}

Creating "1pxImageSharp.tif" with .Net 6:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.PixelFormats;
using Image<Rgba32> image = new(1, 1);
TiffEncoder tiffEncoder = new()
{
    Compression = SixLabors.ImageSharp.Formats.Tiff.Constants.TiffCompression.None
};
image.SaveAsTiff(filePath);

I attach both images for comparison (Compression.None), a txt file with streams decoded to hexdec and a screenshot from Media Info. As I mentioned before 1pxSystemWindowsMedia can be imported with Premiere Pro without Issues, 1pxImageSharp cannot. Bytes.txt MediaInfo TiffImages.zip

brianpopow commented 1 year ago

@MaciejSzulborski can you try open this image here again with adobe premiere: imagesharp.zip

We are storing SamplesPerPixel as Long instead of Short, maybe that's what trips of adobe premiere.

MaciejSzulborski commented 1 year ago

File you shared was successfully imported by Adobe Premiere Pro. SamplesPerPixel type must have been the issue.

When can you implement changes in ImageSharp?

brianpopow commented 1 year ago

File you shared was successfully imported by Adobe Premiere Pro. SamplesPerPixel type must have been the issue.

When can you implement changes in ImageSharp?

Great to hear, thanks for testing and providing the example data.

I have already a branch with the changes, but I want to double check one last thing tomorrow before opening up a PR.

MaciejSzulborski commented 1 year ago

That's great news. Thank you for working on this with me, and fixing this issue.

JimBobSquarePants commented 1 year ago

Great work @brianpopow !! 😍

dlemstra commented 1 year ago

It should be a short according to the specs: https://www.awaresystems.be/imaging/tiff/tifftags/samplesperpixel.html