Converting Jpeg images to Bmp - some images come out blue

前端 未结 4 1038
忘了有多久
忘了有多久 2020-12-14 12:33

There are some Jpg images which Delphi doesn\'t seem to like. It appears to be specific with the files I\'m loading. And the procedure is simple - a) load Jpg image to

4条回答
  •  遥遥无期
    2020-12-14 12:43

    Prompted by your other question, here's some code to load a JPG file to a bitmap and conditionally apply a correction to the resulting bitmap. Please note this works for your Brown.JPG image, but I have no idea what's in those first 18 bytes, so I have no idea if this is going to work long-term or not. I'd personally prefer the use of ready-made, known-to-work, widely used library. Alternatively I'd use David's idea of using WIC if available and reverting to this style of hacky code if not available.

    Here's the full unit code, so you can see all the used units. The form only expects a single TImage named Image1 on the form, so you can create your form first, put the TImage there, then switch to source code view and copy-paste my code over the Delphi-produced code.

    How the code works:

    The code opens the file with the JPG image, and loads it into a TJpgImage. It then compares the first 18 bytes of the file to a known marker. If there's a match it applies a transformation to each and every pixel of the produced bitmap. Because writing the actual marker constants is difficult there's a routine (CopyConstToClipboard) that takes the bytes from the file, transforms them into a Delphi-style constant and copies that to the clipboard. When you find a new file that doesn't work you should use this routine to prepare a new constant.

    Actual code:

    unit Unit9;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ExtCtrls, Jpeg, Clipbrd;
    
    type
      TForm9 = class(TForm)
        Image1: TImage;
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form9: TForm9;
    
    implementation
    
    {$R *.dfm}
    
    type
      TRGB_Pixel = packed record
        B1: Byte;
        B2: Byte;
        B3: Byte;
      end;
      TScanLine = array[0..(System.MaxInt div SizeOf(TRGB_Pixel))-1] of TRGB_Pixel;
      PScanLine = ^TScanLine;
    
    procedure CopyConstToClipboard(const FB:array of byte);
    var s: string;
        i: Integer;
    begin
      s := 'Name: array[0..' + IntToStr(High(FB)) + '] of Byte = ($' + IntToHex(FB[0], 2);
      for i:=1 to High(FB) do
        s := s + ', $' + IntToHex(FB[i],2);
      s := s + ');';
      Clipboard.AsText := s;
    end;
    
    function LoadJpegIntoBitmap(const FileName:string): TBitmap;
    var F: TFileStream;
        Jpg: TJPEGImage;
        FirstBytes:array[0..17] of Byte;
        y,x: Integer;
        ScanLine: PScanLine;
    const Marker_1: array[0..17] of Byte = ($FF, $D8, $FF, $EE, $00, $0E, $41, $64, $6F, $62, $65, $00, $64, $00, $00, $00, $00, $00);
    
      procedure SwapBytes(var A, B: Byte);
      var T: Byte;
      begin
        T := A;
        A := B;
        B := T;
      end;
    
    begin
      F := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
      try
        Jpg := TJPEGImage.Create;
        try
          Jpg.LoadFromStream(F);
          F.Position := 0;
          F.Read(FirstBytes, SizeOf(FirstBytes));
    
          // CopyConstToClipboard(FirstBytes); // Uncomment this to copy those first bytes to cliboard
    
          Result := TBitmap.Create;
          Result.Assign(Jpg);
    
          if (Result.PixelFormat = pf24bit) and CompareMem(@Marker_1, @FirstBytes, SizeOf(FirstBytes)) then
          begin
            for y:=0 to Result.Height-1 do
            begin
              ScanLine := Result.ScanLine[y];
              for x:=0 to Result.Width-1 do
              begin
                SwapBytes(ScanLine[x].B1, ScanLine[x].B3);
              end;
            end;
          end;
    
        finally Jpg.Free;
        end;
      finally F.Free;
      end;
    end;
    
    procedure TForm9.FormCreate(Sender: TObject);
    var B: TBitmap;
    begin
      B := LoadJpegIntoBitmap('C:\Users\Cosmin Prund\Downloads\ABrownImage.jpg');
      try
        Image1.Picture.Assign(B);
      finally B.Free;
      end;
    end;
    
    end.
    

提交回复
热议问题