473,569 Members | 2,590 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Add an EXIF/JPG thumbnail to a jpg

tlhintoq
3,525 Recognized Expert Specialist
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 13194
Plater
7,872 Recognized Expert Expert
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 Recognized Expert Specialist
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 Recognized Expert Expert
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 Recognized Expert Specialist
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 Recognized Expert Top Contributor
@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 Recognized Expert Specialist
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 (JPEGInterchang eFormat,
JPEGInterchange FormatLength) 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 Recognized Expert Expert
Have you checked out the msdn sections on exif? They seemed to be incomplete(poss ibly 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 Recognized Expert Specialist
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 ThumbnailCompre ssion 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 Recognized Expert Expert
I understood type 6 to mean it was a serialization of an object
(Such as perhaps an "enum" as I would assume the ThumbnailCompre ssion Property is)
Oct 30 '09 #10

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

Similar topics

1
3641
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
9401
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 reduce the Traffic, because users don't need to upload the whole Picture because of an missing, or bad Value of EXIF Data. But i still can't find...
0
1890
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 recent call last): File "/Users/Shared/bin/exiftool.py", line 148, in ? tags=EXIF.process_file(f)
4
14202
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
4938
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 solution would be downloading the whole target file locally and then call exif_read_data() but that means a lot of overhead traffic
14
5207
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
8153
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 info: These photos come from a Nikon high end SLR digital camera. It's not my camera so I have no control over how the image is taken. If I open a...
2
2908
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 can´t. I found this "table": Full table is there: http://owl.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html **************** Tag ID Tag Name ...
1
2754
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 perspective, shadows, rounded corners, ... and more in minutes instead of hours or days if you do it manually. Phatch allows you to use EXIF and IPTC tags...
0
7701
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7615
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8130
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7677
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
1
5514
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 presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
3653
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
2115
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1223
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
940
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

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.