473,399 Members | 2,278 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,399 software developers and data experts.

Add an EXIF/JPG thumbnail to a jpg

tlhintoq
3,525 Expert 2GB
I'd like to think I can work out most issues, but this one is kicking my butt.
What's worse, is that I know I can't be the first guy to want to add a thumbnail to jpg that doesn't already have one. I see it in plenty of other applications. Yet I can't seem to make it work despite being so very close.

I know the problem has to be in how I am making the PropertyItem of the thumbnail - because if I comment out lines 24-34 the JPG saves fine, just without a built-in thumbnail.

So I'm either wrong between lines 8-14 where I convert the bitmap NewThumbnail into a byte array, or I'm wrong in how I'm making the thumbnail property.

But for the life of me I can't seem to work it out.

Any assistance in this would be greatly appreciated.

Expand|Select|Wrap|Line Numbers
  1.         public static void WriteNewThumbnailInImage(string Filename, Bitmap NewThumbnail)
  2.         {
  3.             Bitmap Pic;
  4.             PropertyItem[] PropertyItems;
  5.             string FilenameTemp;
  6.  
  7.  
  8.             #region Turn bitmap into an array of bytes
  9.             MemoryStream thumbstream = new MemoryStream();
  10.             NewThumbnail.Save(thumbstream, ImageFormat.Jpeg);
  11.             byte[] Thumb = thumbstream.ToArray();
  12.             //// copy thumbnail into byte array
  13.             //for (i = 0; i < Thumb.Length; i++) Thumb[i] = (byte)Thumb[i];
  14.             #endregion Turn bitmap into an array of bytes
  15.  
  16.  
  17.             #region Read JPG from HDD - it was saved with no EXIF
  18.             Image TempImage = Image.FromFile(Filename);
  19.             Pic = (Bitmap)TempImage.Clone();
  20.             TempImage.Dispose();
  21.             #endregion Read JPG from HDD - it was saved with no EXIF
  22.  
  23.  
  24.             #region If comment this out then the final image saves fine, but with no built-in thumbnail
  25.             //put the new Thumbnail into the right property item
  26.             PropertyItems = Pic.PropertyItems;
  27.             //PropertyItems[0].Id = 0x010e; // 0x010e as specified in EXIF standard for DESCRIPTION
  28.             PropertyItems[0].Id = 20507;// Every example uses this as the READ location for EXIF thumbnail.
  29.             //PropertyItems[0].Type = 1; // 1 = Array of bytes
  30.             PropertyItems[0].Type = 6; // 6 = Array of bytes that can hold any data type
  31.             PropertyItems[0].Len = Thumb.Length;
  32.             PropertyItems[0].Value = Thumb;
  33.             Pic.SetPropertyItem(PropertyItems[0]);
  34.             #endregion If comment this out then the final image saves fine, but with no built-in thumbnail
  35.  
  36.  
  37.             // we cannot store in the same image, so use a temporary image instead
  38.             FilenameTemp = Filename + ".temp";
  39.             try
  40.             {
  41.                 using (EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)70))
  42.                 {// Encoder parameter for image quality
  43.  
  44.  
  45.                     // Jpeg image codec
  46.                     ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg");
  47.  
  48.                     if (jpegCodec == null)
  49.                         return;
  50.                     EncoderParameters encoderParams = new EncoderParameters(1);
  51.                     encoderParams.Param[0] = qualityParam;
  52.  
  53.                     Pic.Save(FilenameTemp, jpegCodec, encoderParams);
  54.  
  55.                 }
  56.  
  57.             }
  58.             catch (Exception emg)
  59.             {
  60.                 Console.WriteLine("EXIF #####################################################");
  61.                 Console.WriteLine(emg.Message);
  62.                 Console.WriteLine(emg.StackTrace);
  63.             }
  64.  
  65.  
  66.             return;
  67. }

Of course error messages that don't tell you much don't help either.
Yippee, a generic error - let me track that right down.
Expand|Select|Wrap|Line Numbers
  1. A generic error occurred in GDI+.
  2.    at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
  3.    at WriteNewThumbnailInImage(String Filename, Bitmap NewThumbnail)
  4. [...]
  5. A first chance exception of type 'System.Runtime.InteropServices.ExternalException' occurred in System.Drawing.dll
  6. The thread 0x15dc has exited with code 0 (0x0).
Oct 28 '09 #1
15 13151
Plater
7,872 Expert 4TB
I have never been able to modify/add PropertyItems to a Bitmap in .NET
I was just thinking about asking the other day if anyone knew how.
I always get the GDI+ error.


The thumbnail thing in particular I find interesting as I have some images whos thumbnails have no relation to the actual image. Which makes it very confusing.


Just looked up the constants, I think you need to supply more then just thumbnail data:
(From my ENUM)
Expand|Select|Wrap|Line Numbers
  1. PropertyTagThumbnailFormat = 0x5012,
  2.             PropertyTagThumbnailWidth = 0x5013,
  3.             PropertyTagThumbnailHeight = 0x5014,
  4.             PropertyTagThumbnailColorDepth = 0x5015,
  5.             PropertyTagThumbnailPlanes = 0x5016,
  6.             PropertyTagThumbnailRawBytes = 0x5017,
  7.             PropertyTagThumbnailSize = 0x5018,
  8.             PropertyTagThumbnailCompressedSize = 0x5019,
  9.             PropertyTagColorTransferFunction = 0x501A,
  10.             PropertyTagThumbnailData = 0x501B,
  11.             PropertyTagThumbnailImageWidth = 0x5020,
  12.             PropertyTagThumbnailImageHeight = 0x5021,
  13.             PropertyTagThumbnailBitsPerSample = 0x5022,
  14.             PropertyTagThumbnailCompression = 0x5023,
  15.             PropertyTagThumbnailPhotometricInterp = 0x5024,
  16.             PropertyTagThumbnailImageDescription = 0x5025,
  17.             PropertyTagThumbnailEquipMake = 0x5026,
  18.             PropertyTagThumbnailEquipModel = 0x5027,
  19.             PropertyTagThumbnailStripOffsets = 0x5028,
  20.             PropertyTagThumbnailOrientation = 0x5029,
  21.             PropertyTagThumbnailSamplesPerPixel = 0x502A,
  22.             PropertyTagThumbnailRowsPerStrip = 0x502B,
  23.             PropertyTagThumbnailStripBytesCount = 0x502C,
  24.             PropertyTagThumbnailResolutionX = 0x502D,
  25.             PropertyTagThumbnailResolutionY = 0x502E,
  26.             PropertyTagThumbnailPlanarConfig = 0x502F,
  27.             PropertyTagThumbnailResolutionUnit = 0x5030,
  28.             PropertyTagThumbnailTransferFunction = 0x5031,
  29.             PropertyTagThumbnailSoftwareUsed = 0x5032,
  30.             PropertyTagThumbnailDateTime = 0x5033,
  31.             PropertyTagThumbnailArtist = 0x5034,
  32.             PropertyTagThumbnailWhitePoint = 0x5035,
  33.             PropertyTagThumbnailPrimaryChromaticities = 0x5036,
  34.             PropertyTagThumbnailYCbCrCoefficients = 0x5037,
  35.             PropertyTagThumbnailYCbCrSubsampling = 0x5038,
  36.             PropertyTagThumbnailYCbCrPositioning = 0x5039,
  37.             PropertyTagThumbnailRefBlackWhite = 0x503A,
  38.             PropertyTagThumbnailCopyRight = 0x503B,
  39.  
Oct 28 '09 #2
tlhintoq
3,525 Expert 2GB
Just looked up the constants, I think you need to supply more then just thumbnail data:
(From my ENUM)
Yeah... I was kinda trying to bury my head in the sand about all of those.
I know many are optional, just as they are optional in the primary image the EXIF is a part of. EquipMake, EquipModel, Artist and so on.

Since I can read an exif thumbnail without having to look up any of the other properties I was expecting to be able to write it without any of the other properties.

Property 20507 (0x501B) is ThumnailData, which is all I use to get the EXIF thumbnail.

Hmm... I'm just out of ideas. I guess I'll walk away from this issue for a day then attack it fresh.
Oct 28 '09 #3
Plater
7,872 Expert 4TB
Well you might be able to read the byte[] in thumbnailData, but something else has to go on to know the dimensions of the bitmap for reconstruction right?
Oct 28 '09 #4
tlhintoq
3,525 Expert 2GB
The byte array created is the image saved to a memory stream. So it is a complete image including the file header, size, color depth etc, just as if it were a file saved to disk.

Then you read the complete byte array back, and turn it into an image again by reading the byte array from memory stream just as if reading from disc.

I'm still working the problem... slowly gaining on it. Though I am about to gain on it with my AR-15
Oct 28 '09 #5
GaryTexmo
1,501 Expert 1GB
@tlhintoq
Off topic, but...

I know I certainly feel like that some days, especially with my current work project. *sigh*

:)
Oct 28 '09 #6
tlhintoq
3,525 Expert 2GB
So after a day of beating on it I've made some progress. At this point I can successfully put a BMP in as a thumbnail and retrieve it. But not a jpg. And not to the property number that I have alway seen documented as the thumbnail property. (But it is the property number used by Apple's iPhoto for the thumbnail which I would have expected to follow industry specification since they helped design it)

Here's what I have learned so far:
You can add properties and give them values. The values will be seen and not show an error, but apparantly if they are not formed in a way that is expected for EXIF they won't be written and you won't get any error messages most times. Take this example. I added what I thought would be the thumbnail and a another property for 'description'. They can be seen pre-write to the HDD but when read back the description is still present but the thumbnail was not.



I can't find any documentation on how exactly to format the data for each property, or when one 'type' is used over another. "A property type of 1 is an array of bytes. A property type of 6 is an array of bytes that can be used for any purpose."
In this case the Compression tag value is set to "6" and tags in the 1st IFD (JPEGInterchangeFormat,
JPEGInterchangeFormatLength) are used to designate the location and size.
But the specifications document doesn't tell you if it should be a type 2 ascii "6", or a type 1 byte with a value of 6, or a type 6 byte of 6, or an int of 6 converted to a byte array.

So what I did was export a JPEG out of Apple's iPhoto with all the descriptions and other fields set to something. This gave me a total of 41 properties in the EXIF of the JPG. Now it's just a matter of reverse engineering what they do. But at least I have them, with their types and lengths and values. This will be my Rosetta Stone.
Oct 29 '09 #7
Plater
7,872 Expert 4TB
Have you checked out the msdn sections on exif? They seemed to be incomplete(possibly just old?) as I found another reference with an extra 100 or so id tag types.
I have enums for both the tagIDs and the value types

For value types, including the brief description of it
Expand|Select|Wrap|Line Numbers
  1. private enum ImagePropertyTagValueTypes
  2.         {
  3.             ArrayOfBytes=1,
  4.             ASCIIString=2,//If you set the type data member to ASCII type, you should set the Len property to the length of the string including the null terminator. For example, the string "Hello" would have a length of 6.
  5.             ArrayOfUnisignedShort=3,//16bit ints
  6.             ArrayOfUnisignedLong=4,//32bit ints
  7.             ArrayOfPairUnsignedLong=5,//(64bits) Each pair represents a fraction; the first integer is the numerator and the second integer is the denominator.
  8.             ArrayOfObjectBytes=6,//bytes that can hold values of any data type.
  9.             ArrayOfSignedLong=7,//32bit ints
  10.             ArrayOfPairSignedLong=10,//(64bits) Each pair represents a fraction; the first integer is the numerator and the second integer is the denominator.
  11.         }
  12.  
Oct 29 '09 #8
tlhintoq
3,525 Expert 2GB
I have a very similar list from the MSDN page
Expand|Select|Wrap|Line Numbers
  1.         /// <remarks>             
  2.         /// * Additionally, this MSDN page details more information, specifically that 
  3.         ///     * JPEG images must have a width and height in multiples of 16 in order to have 
  4.         ///     * completely "lossless" rotation:
  5.         ///http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/usingGDIPlus/usingimageencodersanddecoders/transformingajpegimagewithoutlossofinformation.asp
  6.         ///The following table shows integers and the types they represent.
  7.         ///1-Specifies that Value is an array of bytes.
  8.         ///2-Specifies that Value is a null-terminated ASCII string. If you set the type data member to ASCII type, you should set the Len ///property to the length of the string including the null terminator. For example, the string "Hello" would have a length of 6.
  9.         ///3-Specifies that Value is an array of unsigned short (16-bit) integers.
  10.         ///4-Specifies that Value is an array of unsigned long (32-bit) integers.
  11.         ///5-Specifies that Value data member is an array of pairs of unsigned long integers. Each pair represents a fraction; the first integer is the numerator and the second integer is the denominator.
  12.         ///6-Specifies that Value is an array of bytes that can hold values of any data type.
  13.         ///7-Specifies that Value is an array of signed long (32-bit) integers.
  14.         ///10-Specifies that Value is an array of pairs of signed long integers. Each pair represents a fraction; the first integer is the numerator and the second integer is the denominator.
  15.         ///For more information about property tags, see "Image Property Tag Constants" in the MSDN library at http://msdn.microsoft.com/library.
  16.         ///</remarks>
  17.  
But I like how your enum better spells out the intended use for each type.
Though I am still a little fuzzy how how they are differentiating their needs and uses. Based on the magic disappearing property experience I mentioned earlier I can only conclude that some validation is taking place before writing *based* on the type specified. No error gets returned if there is a problem: Just that the property doesn't get written into the file.

So I still wonder is there any documentation on when to use a given type for a given property? I mean, bytes are bytes: They hold values between 0-255.
So what makes type 1 bytes different from type 6 bytes. How are we supposed to know that if the property is a ThumbnailData you have to use type 6 bytes instead of type 1 bytes.

For the ThumbnailCompression property you are supposed to assign a value of "6". Ok, but in why type or manner?
I can write a 6 as an ASCII "6", that would be a type 1 string.
I can write a 6 as a short(3), long(4),ulong(7), or just a byte of value 6 would could be type 1 or type 6.

Through a lot of trial and error I was able to reverse engineer how to put in a non-compressed thumbnail in bitmap format. But it makes s 230kb jpg file into a 1,439 kb file. The uncompressed thumbnail data is actually larger than the compressed image.

A lot more trial and error and I will eventually have the magic combination for using a jpeg thumbnail inside a jpeg image. It just bothers me that I have to spend 2 days sussing this out when there should be rules and documentation available to developers for these types of things.
Oct 30 '09 #9
Plater
7,872 Expert 4TB
I understood type 6 to mean it was a serialization of an object
(Such as perhaps an "enum" as I would assume the ThumbnailCompression Property is)
Oct 30 '09 #10
tlhintoq
3,525 Expert 2GB
I finally found an explanatin of property ID and propety type to use for. The EXIF 2.2 specification PDF. Imagine that. But geez these guys went out of the way to make that document hard to understand and still lacks a great deal of practical info.

ThumbnailCompression according to the spec is merely set to 1 if not and 6 if jpg compression. No other description about it.

Right now I've gotten this to read and write JPEG thumbnail into EXIF data of a JPEG image. Hurray! The only part I am hesitant about is that it isn't in the property that I have always seen used for thumbnails: 20507. What is working is working in property 34675. The exact same code that works into 34675 does not work if I change the ID to 20507 and re-run it. Totally weird. By the way, no other property had to be set to anything. 34675 will accept the byte[] from Image.save(memorystream). Which makes sense as the saved memory stream contains all the info needed to read and translate a compressed JPG.
Oct 30 '09 #11
Plater
7,872 Expert 4TB
Wierd, 34675 I have listed as PropertyTagICCProfile
Nov 2 '09 #12
tlhintoq
3,525 Expert 2GB
yah... Exactly what I'm saying. It's weird, but it works. Right now this is intended for an in-house proprietary set of applications. So as long as application 'a' can find the thumb where application 'b' puts it, then all is good. But in the long run I would like to do it *right* and have things compatible with all other applications that actually follow industry standards.
Nov 2 '09 #13
tlhintoq
3,525 Expert 2GB
Ok. Finally got this working. Little tidbit that is hard to find: The maximum size allowed is 160x160 and must be in the same aspect ratio as the full size image.

Expand|Select|Wrap|Line Numbers
  1. #region Create a new standard thumbnail property.
  2. //Max of 160x160 in same aspect ratio as main image
  3. Image SmallThumb = tlhintoq.GDI.Graphics.CalculatedThumbnail(NewThumbnail, 160, 160);
  4. MemoryStream MS = new MemoryStream();
  5. SmallThumb.Save(MS, ImageFormat.Jpeg);
  6. SmallThumb.Dispose();
  7. MS.Position = 0;
  8. byte[] smallthumbbytes = MS.ToArray();
  9.  
  10. PropertyItems = Pic.PropertyItems;
  11. PropertyItems[0].Id = 0x501b; // PropertyTage ThumbnailData
  12. PropertyItems[0].Type = 1;
  13. PropertyItems[0].Len = smallthumbbytes.Length;
  14. PropertyItems[0].Value = smallthumbbytes;
  15. Pic.SetPropertyItem(PropertyItems[0]);
  16.  
  17. #region Create a new Thumbnail Compression property.
  18. PropertyItems = Pic.PropertyItems;
  19. PropertyItems[0].Id = 0x5023; // PropertyTagThumbnailCompression
  20. PropertyItems[0].Type = (short)ImagePropertyTagValueTypes.ArrayOfUnisignedShort3;
  21. PropertyItems[0].Len = 2;
  22. PropertyItems[0].Value = new byte[] { 6, 0 };
  23. Pic.SetPropertyItem(PropertyItems[0]);
  24. #endregion
Nov 2 '09 #14
Plater
7,872 Expert 4TB
So now your thumbnails will be read by windows in the file explorer yes?
Nov 2 '09 #15
tlhintoq
3,525 Expert 2GB
They seem to be. SInce Windows7 tries to build new thumbs even if there is no EXIF included, then stick them in the thumbsdb I can only go by the speed. But it seems to be working.

I guess I should dig up a program that is known to load the industry standard thumb and display it.
Nov 2 '09 #16

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Phil Powell | last post by:
PHP 4.3.2 with --enable-exif I have the following class: <?php class ThumbGenerator extends MethodGeneratorForActionPerformer { function ThumbGenerator() { // CONSTRUCTOR
4
by: Jan Schmidt | last post by:
Hi NG, i created my own Picture Gallery, which reads the EXIF Data of each Picture before displaying on website. I'd like to give my users the ability to alter some opened EXIF Values. It would...
0
by: leo | last post by:
hi there i'm using gene cash's EXIF.py module to find out the shoting time of an jpeg image. this module works usually like a beauty, but some images raise an exception: Traceback (most...
4
by: thomas kern | last post by:
Hello, i dont know how to extract the thumbnail of an image? is there a good way to do that cos there arent many articles on the internet :/ thank you thomas
1
by: Alfonso Acosta | last post by:
Hi all, exif_read_data() doesn't support URLs (http://php.net/manual/en/function.exif-read-data.php ) but I would like to do that with the minimum traffic and overhead possible. A naive...
14
by: Frank | last post by:
I see that ImageFormat includes exif. But I can't find out if I've System.Drawing.Image.FromStream or something like it can read and/or write that format.
2
by: Milagro | last post by:
Hi, I'm using the code below to create thumbnails from photos. The code works fine and thumbnails are created. However, thumbnails of vertical photos are oriented as horizontal photos. More...
2
by: iKER- | last post by:
Hi! I´m working in a program witch need to read Exif data from my Sony Alpha A100 raw (arw extension) pictures. I found a table with keys for read it, but i can´t read. I tried something, but i...
1
by: SPE - Stani's Python Editor | last post by:
Phatch is a simple to use cross-platform GUI Photo Batch Processor Phatch handles all popular image formats and can duplicate (sub)folder hierarchies. It can batch resize, rotate, apply...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.