-1

I have been around the world twice and a half trying to fix a strange issue with a large sum of images I have.

What I need is to know how to read and write the first 4 and 18th bytes in the header of a JPEG file. If they match certain properties, I need to do some certain work and tweak these bytes to reflect something else. I'm basically fixing the format of these pictures to a more standard format, as Delphi doesn't recognize the format they're in.

So how do I read/write these bytes? What do I use? I know nothing about reading the raw data of an image file, let alone tweaking it.


NOTE

Deleted most of the question as I had put way too much information from the start.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • 2
    This isn't really a question, is it? You're asking for someone to write code for you. For free. – cha0site Jan 19 '12 at 22:11
  • I'm asking how to read/write certain bytes in the header of a JPEG file. That's it. Shouldn't be that hard. – Jerry Dodge Jan 19 '12 at 22:14
  • You would be far better off getting a decoder that handled the images. Modifying the files seems bad. – David Heffernan Jan 19 '12 at 22:14
  • Let's see the code that you're using to load the images now. I need to see if you're loading from a file, or what. The files are fine, we'll just have to get them to render properly in Delphi. – Marcus Adams Jan 19 '12 at 22:23
  • @MarcusAdams The code is in the original question, and is extremely straight-forward. a) load from JPEG image, b) assign to BMP image, and c) display image. As far as loading the file for modifying the header, I don't even know how to do this in the first place. – Jerry Dodge Jan 19 '12 at 22:25
  • 1
    @Jerry: JPEG doesn't actually have a straight-forward header, it has frames which may contain "markers". The relevant standards are [ITU T.81](http://www.w3.org/Graphics/JPEG/itu-t81.pdf) (The relevant bits are in Annex B, page 31) and [JFIF 1.02](http://www.w3.org/Graphics/JPEG/jfif3.pdf). Please note how complex these standards are. What you're asking is _not_ that simple, especially without a 3rd party library like you're asking. I'd suggest fixing the files, using a tool such as [ImageMagick](http://www.w3.org/Graphics/JPEG/jfif3.pdf). This should be simpler. – cha0site Jan 19 '12 at 22:31
  • @Jerry, what are you doing with the images after you load them? Are you simply displaying them in a TImage? – Marcus Adams Jan 19 '12 at 22:34
  • @MarcusAdams We have a common class in our software called a `TEImage` which we use for holding pictures. Within this class, it maintains a thumbnail file reference, meaning that it has to save this file to the hard disk. At the same time, we also read this image to display it too. So I do many different things with images after they're loaded into this object. – Jerry Dodge Jan 19 '12 at 22:38
  • 2
    @Jerry: Please note [ImageMagick's license](http://www.imagemagick.org/script/license.php). Creating your own tool which includes ImageMagick and uses it internally (it has an API to many programming languages) and giving that to your customers would _still_ easier, by several orders of magnitude, than what you're asking right now. I don't think you understand what you're asking for here. – cha0site Jan 19 '12 at 22:39
  • @Jerry You seem in a bit of a tizz over this one. Perhaps you should slow down a bit and reflect. I have found it frustrating how the question keeps morphing. You seem to take offence whenever anyone suggests a solution different to the one you are currently thinking of. But then each question brings a new slant on your thinking. – David Heffernan Jan 19 '12 at 22:40
  • 1
    @Jerry: Well, if you don't want any 3rd party stuff, then what you're asking for is for someone to write you a JFIF decoder (granted, just the metadata, and not the image DCT stuff). This is no small task, and way beyond the scope of SO. – cha0site Jan 19 '12 at 22:51
  • Jerry, buy a commercial or shareware image library, or see if [Graphics32](http://http://sourceforge.net/projects/graphics32) will work with the images you have. Expecting someone to do this level of work (after wading through the tons of text) is really too much, especially since no one here has the images you're dealing with (and don't suggest putting them somewhere for us to download). This isn't a real question; it's a "please send me the code" question. – Ken White Jan 19 '12 at 23:01
  • @jerry if all you need to do is tweak the first 18 bytes you can do it yourself. How hard can it be? And do it with a stream wrapper class so you don't need to change files on disk. – David Heffernan Jan 19 '12 at 23:06
  • I deleted most of my question and re-asked with only the specific things I need answered. I'm also deleting my comments which were related to the previous question, and would advice others to as well please. Sorry for the confusing start to this question. – Jerry Dodge Jan 19 '12 at 23:24

4 Answers4

3

Don't even think you can tweak manually the first x bytes of your jpeg files.

As it has been explained already, the jpeg format is multiform and very complex. So much that some commonly used libraries do not handle all the acceptable formats. Open a libjpeg.h and see the bunch of header structures you can find in a jpeg file.

If you want to modify your header without changing the data, you still have to open the jpeg with a library that will hand over the proper structures for you to modify the relevant flags and save it back with the wanted format.

Either find a library written in Delphi or with a Delphi interface and use it to build your batch converter or to transform the format on the fly when opening a jpeg in your application.

If you know the exact combination of properties/flags defining your problem files, you can tweak the jpeg.pas unit to suit your need as I've shown in the previous answer.

Community
  • 1
  • 1
Francesca
  • 21,452
  • 4
  • 49
  • 90
3

The mechanics of actually changing the JPG header are very easy. That doesn't mean fixing the JPG is easy, it's just that if you know what to change, you can easily do it. Since that's what you're asking, here's how to change the JPG header in-memory, load the modified JPG into a TJpgImage and convert to TBitmap.

Please note I don't think this is a good approach. Fixing the resulting bitmap is so much easier! See my fresh answer to your other question for how to fix the bitmap here.

And here's the code you asked for (how to change the JPG header):

function LoadJpegIntoBitmap_HeaderFix(const FileName:string): TBitmap;
var M: TMemoryStream;
    P: PByteArray;
    Jpg: TJPEGImage;
begin
  M := TMemoryStream.Create;
  try
    M.LoadFromFile(FileName);
    if M.Size < 18 then raise Exception.Create('File too short.');
    P := M.Memory;

    // Here you can manipulate the header of the JPG file any way you want.
    if P[0] = $07 then P[3] := P[17] - P[0]*3;

    // Now load the modified JPG into a TJpgImage
    Jpg := TJPEGImage.Create;
    try
      Jpg.LoadFromStream(M);

      // Convert to bitmap
      Result := TBitmap.Create;
      Result.Assign(Jpg);

    finally Jpg.Free;
    end;

  finally M.Free;
  end;
end;
Community
  • 1
  • 1
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
  • Thank you, the only answer here which had anything to do with my question. People here should not worry about *why* I'm doing what I'm doing, my question clearly states a simple task. I tried deleting my question but couldn't because of one very sarcastic answer. It's the fact that people were taking my question 1 million miles off topic that got me heated. – Jerry Dodge Jan 20 '12 at 17:27
2

Here's some pseudo code really quick. I'll improve it later. I have to run.

Assign the Adobe JPEG image file to a TFileStream
Read first 18 bytes and use CompareMem to see if signature matches Adobe RGB JPEG
If RGB JPEG then
  We'll either:
    Load from stream and tweak the header as we load
  OR
    Load from stream, copy to TBitmap, and use ScanLine to fix RGB
Else
  Load from stream, normally

Hint, see LoadFromStream() instead of LoadFromFile().

I don't know what you're doing with the image afterward, so there may be some more work to be done.

Marcus Adams
  • 53,009
  • 9
  • 91
  • 143
  • This is nice pseduo-code, but the devil is in the details. I don't know what `TBitmap` is, but if it takes care of decoding JPEG, then that might be the way to go - handling the data in bitmap form would be much easier than tweaking the JFIF "header". – cha0site Jan 19 '12 at 22:54
  • It's the most standard (in delphi) graphic object there is. Everything works with a `TBitmap`. – Jerry Dodge Jan 19 '12 at 23:02
  • @jerry cha0site has every business commenting. Your comment was quite impertinent. – David Heffernan Jan 19 '12 at 23:08
  • @Jerry: Check out this sample code on [How to find an unused color](http://www.awaresystems.be/techtalks/004_unused_color.html). They're demonstrating taking pixels and splitting them into component colors. You could probably use a similar approach to reverse the colors into BGR. – cha0site Jan 19 '12 at 23:14
  • @cha0site Thanks, but I already know how to swap the RGB/BGR bytes. I shouldn't have even mentioned anything about this RGB problem in this question because really all I need to know is how to read/write the header of a JPEG. – Jerry Dodge Jan 19 '12 at 23:17
  • @Jerry: Then I'm afraid we're back to step 1: Me telling you that this is crazy magic level stuff best left to libraries, and you insisting that it is simple. =( – cha0site Jan 19 '12 at 23:20
  • @cha0site Reading and writing the first 18 bytes of a file should not be difficult. I'm estimating not even 20 lines of code. – Jerry Dodge Jan 19 '12 at 23:27
  • @Jerry: Delphi imaging? What about a dozen Google searches just taught me. JPEG, JFIF, EXIF, and ICC profiles? Quite a bit more. I'll be quite surprised if Delphi has, in its standard library, a facility for handling every bit of functionality JPEG has to offer, especially ICC profiles. If you want to read the bytes, then parse and modify them by hand, let me just suggest that you're not going to get any useful results in a reasonable timeframe. You really should use a library for this. If you want a Delphi library, here is one: [nativejpg](http://www.simdesign.nl/nativejpg.html). – cha0site Jan 19 '12 at 23:45
  • 3
    @Jerry Nothing unusual here. You have code. You have projects. You have developers. That's software development. You build it in Delphi. That's third party. Nobody can understand why you reject working solutions that involve other people's solutions. If you insist on doing it yourself then you need to learn all about the jpeg file format. That's a huge task. You won't do it asking questions like this. Get the docs and start reading. – David Heffernan Jan 20 '12 at 07:47
2

Right, so your options here are (since we've completely ruled out any 3rd party code whatsoever):

  1. Some Delphi guru (which I am certainly not) coming out of the woodwork and illuminating us with the existence of standard Delphi library code which handles this, or,
  2. You write your own JPEG metadata decoding library.

Since I can't help you with the first option, here are some references you'll need while pursuing the second:

  • Wikipedia's JPEG article - one of the better written articles on the wiki. Great introductory material to this hairy subject.
  • ITU T.81 - The original JPEG specification. The most important bit is in Annex B, but this actually describes a format known as JIF which isn't actually in use. However, both JFIF and EXIF are based on it.
  • ICC - This specifies ICC (International Color Consortium) profiles, which are the bit that seems to be wrong with your headers.
  • ICC 2010 - New version of above specification, with Errata.
  • JFIF - The format most JPEG files actually use.
  • EXIF - Another format JPEG files use, especially those originating from digital cameras.
  • ITU T.84 - Less useful, this describes JPEG extensions. I'm including it here for completeness.

Sadly, none of the public domain JPEG implementations that I'm aware of (in any language) actually handle the relevant bits of the standards, namely EXIF and ICC profiles, so I can't give you any code you could draw inspiration from. The best place to look would probably be libexif, but that's GPL'ed.

What you're going to want to do is to read in the JPEG file as a regular file, parse the input according to information gleaned from the above documents, make the necessary changes, and write it back out. I don't think this is going to be easy, but apparently this is the only solution you'll accept.

Good luck!

cha0site
  • 10,517
  • 3
  • 33
  • 51