Detect Image Type

Assume you have a Picture variable with some content. It might be a PNG or a JPEG or a TIFF.

Is there a way to detect which Type it is? I can write the code to make this determination if I have the folderItem of some file on disk but once you have a Picture variable can you determine the Type?

Or perhaps this is just a meaningless question. Perhaps a Picture variable intrinsically is not a JPEG or TIFF or whatever.

No, its just pixels.

That is correct . A Picture varible has been expanded into an uncompressed bitmap. You can save it in any format you want, for example. If you need to know the original format, you would have to go back to the folderitem you loaded it from.

1 Like

Unless you have the original data that the picture is create from, where you can poke around to find the identifiers, I don’t think there’s a way to get that data out of the Xojo Picture class. A utility like ExifTool is massive overkill but it’s very good at determining image type.

1 Like

Maybe this old forum entry helps: Need help identifying picture format

Thanks for the many responses. A Picture Object in Xojo consists of only pixel data—it is not inherently a JPEG, TIFF, or PNG. Trying to determine its format makes no sense because it does not retain any original file type information.

For those who may come across this discussion in the future, I think it’s worth explaining why I originally asked this question. My inquiry was based on a misconception, and clarifying it may help others understand the issue better and avoid the same trap.

I was initially interested in Base64 encoding as a way to embed images directly into my application (as Constants) instead of relying on linked external files. One of my concerns was the size of these Base64-encoded text files. After some research, I found that Base64 encoding increases the file size by about 35–40%, which isn’t too troublesome.

This led me to wonder whether using JPEG images for Base64 encoding was more efficient than using uncompressed images. I soon learned that it is generally better to encode JPEGs rather than raw image data when using Base64. You can reduce the amount of text. But just why?

At first, it seemed counterintuitive that a 200x200 pixel image displayed on a Canvas could be smaller in size as a JPEG compared to a Picture Object of a non-compressed image. After all, the number of pixels remains the same regardless of the format. This made me question whether Xojo’s Picture Object was somehow storing images in a JPEG format under certain conditions. That led me to search for a way to determine whether a given Picture Object was originally a JPEG — which, as it turns out, is not possible within Xojo and makes no sense.

[Parnell will be happy to know that ChatGPT confidently misled me on this topic, providing incorrect code for determining a Picture Object’s format.]

I was trying to determine whether a Picture Object was a JPEG, assuming that it somehow retained its original file format. While it’s true that a FolderItem (an actual file) contains metadata identifying it as a JPEG, this information is lost once the image is loaded into a Picture Object in Xojo.

I should have paid more attention when going the other direction, when generating Base64-encoded text from a Picture Object. The EncodeBase64 command requires explicitly specifying the desired format (PNG, JPEG, etc.). That alone should have made me question my worldview, why it was necessary? If the Picture Object already “knew” it was a JPEG, this step wouldn’t be needed.

The Base64 text itself represents either a JPEG, PNG, or another format, but this has nothing to do with the Picture Object itself. The Picture Object will always store raw pixel data, regardless of the file format of it originator. However, the Base64 text size created from EncodeBase64 can vary significantly based on how the encoding is specified.

If your goal is to minimize the size of Base64-encoded text, you should convert the Picture Object to JPEG as you are encoding it, as JPEG compression significantly reduces file size. Later, when decoding the Base64 text back into a Picture Object, the image will be reconstructed from the smaller data source — but this has nothing to do with how the original Picture Object was created (whether from a TIFF, PNG, or JPEG file).

In summary, a Picture Object’s size in memory depends basically on its pixel dimensions — not its original file format. However, the Base64 representation can be much smaller if the image is first converted to JPEG as it is transitioning to Base64 text.

2 Likes

Bear in mind that JPEG is a lossy format, while PNG is not. That means that the more times you change a JPEG into a Picture and save it back, the worse the image will become. You may want to consider PNG as the format if you do this frequently.

5 Likes

In my usage, I will import the original picture as a PNG and then only once transform it into a JPEG when it becomes some Base64 text which I will store in a Constant. After that, well it is a Constant. :slightly_smiling_face:

And it does mean that there is no point in using a JPEG when I do the initial import and indeed, as Hare points points out, that only introduces a slight degradation.

2 Likes

You mention the original images are PNG.
PNG is a lossless compressed format that is generally used for screenshots, icons, vector graphics exported as raster images (vector to pixel).
Unless your original images are actual photos, it might be better to stick with the PNG format.

You already mentioned the slight degradation, so you actually notice it. While it could be an acceptable degradation for you, you might have users like me who abhor JPEG compression because of the visible artifacts around lines, text and shapes.

I’ve already seen PNG files using less disk space than the exact same image saved as JPEG.

In order to save space, I would follow these rules:

  • Original file is JPEG, then stick with JPEG but don’t recompress it.
  • Actual photo: JPEG
  • Large pictures with complex colors: JPEG
  • Small pictures: PNG
  • Anything else: PNG
1 Like

did you consider webp files ?

Here is a link to a comic page stored as webp 0_GarthJULY23.webp

The file is 406Kb (4462 Ă— 1227 pixels @ 72 dpi).
I loaded it with the current GIMP, Export “as is” it to png and the file is 5.9Mb.

This may help your decision process.

BTW: I do not care about the last format “à la mode”; I only look at the quality and file size.

Xojo Picture.Formats enumeration doesn’t support WebP.

That would depend on the quality setting used. At the highest setting the JPEGs use 4:4:4 subsampling and only a modest amount of compression, resulting in no visible degradation.

It may be time they support it.

WebP format os 14 years old. Not the last technology that appeared yesterday.

But you are right, I do not checked that before posting.

Now, there a room to discuss. I just tested with the current released version, and I can see my image in the debugger (Click in Contents display my image, the one I shared). BUT: Graphics is Nil.
I do not explorate more than that.
current MacOS x Sequoia / MacBookPro m1.

To be complete, here’s a code from the documentation:


Var picFile As FolderItem
picFile = FolderItem.ShowOpenFileDialog("")

If picFile <> Nil And picFile.Exists Then
  Var pic As Picture
  pic = Picture.Open(picFile)
  cUSA.Backdrop = pic
End If

I add that to a button to an actual project. The only difference is cUSA instead of ImageWell1.

The image is displayed. All is fine.

Nopw OP choice.

This is true, but could be misleading - Xojo pictures internally can be one of 4 types: Image, Vector, MutableBitmap and ImmutableBitmap.

It would be misleading to say that a Xojo Vector Picture “consists only of pixel data”.

Also, I believe that ImmutableBitmap format might in some cases actually be storing the original image (JPEG, etc.) internally.

Pictures loaded from a file (via Open() ) are immutable. You cannot access their Graphics property. You have to draw them into a New Picture first, then you can use its Graphics.

Let say that my original file is a JPEG. End goal is to have a small Base64 version.

I have already written a small Xojo app to import that JPEG into a Picture and then use the Picture.ToData Method to convert it to a MemoryBlock. When you do this step, you specify what quality JPEG you want in this MemoryBlock. Then you use the EncodeBase64 to take a String to a Base64 encoded String. I have a little but of hand-waving here because I have a MemoryBlock not a String coming out of the Picture.ToData Method but whatever the case it works. The Memory Block is worked on as if it is a String.

But, when I look at this workflow, it seems that I am, in fact, applying the JPEG twice. The original file was already a JPEG. Then I bring it into a Picture which essentially “deJPEG’d” it. And then I take that Picture and JPEG it again as it moves into a MemoryBlock.

JPEG → Picture → MemoryBlock(JPEG’d) → Base64.

Ideally, what I would be doing is just JPEG → Base64 without the intervening “Picture” step. I don’t know that I can write a small app in Xojo that just start with a FolderItem that happens to be a JPEG and converts it to a Base64 text file without the intervening step of making a Picture.

If that is not possible, then for my use case it probably make sense just to bypass Xojo entirely for this function and get a third-party app that does this function. There seems to be a badly reviewed app in the Mac App Store that probably does this. It is an app with In-App Purchases which I personally try and avoid. There may be some way you can do this manually in the Terminal which I might be willing to steel myself to do if I really understood that it would work and was more than a ChatGPT hallucination.

MBS has a PictureToJPEGString function. This is what I use. Then, as you, I Base64Encode the result. Such functionality is also available from Einhugur. Maybe you’re not in the plugin market, but it’s there.

The JPEG file that I open as a Picture:

selectedImage = Picture.Open(fiImage)

does carry the ImmutableBitmap Type. That Bitmap name suggests that it is just Pixels. I cannot find anything in the Documentation to suggest that it “internally” is retaining it as a JPEG. If it is, I don’t think that that would be used in any way when going through the steps to make it a Base64 text file.

Is the input to that function a Picture or a FolderItem? If it is a Picture then I would see that as again “twice” JPEGing the image in my use case scenario.