Forum > Graphics
[SOLVED] Trying to efficiently encode/decode images....
(1/1)
EganSolo:
I want a bit of code that can encode and decode a TImage into a string. I created a simple program with two TImage components, a memo and two buttons: btn_Encode which encodes the content of image1 into a string displayed into the memo and btn_decode which is supposed to take the string in the memo and decode it back into an image to be displayed into Image2 but I've got a bug in that return leg (please see below)
The encoding process, I took from this topic https://stackoverflow.com/questions/57481399/lazarus-timage-to-base64 on Stackoverflow with a minor modification.
--- Quote ---
TBase64EncodingStream is not suitable for big binary conversion, I mean, it will be very slow, also Image1.Picture.SaveToStream, by default, will save the picture as Bitmap format, so it will be very big. Try using JPG format.
--- End quote ---
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.Button1Click(Sender: TObject);var imgstream, Outputstream: TStream; Encoder: TBase64EncodingStream; jpg: TJPEGImage; I: Int64;begin I := GetTickCount64; imgstream := TMemoryStream.Create(); Outputstream := TStringStream.Create(''); jpg := TJPEGImage.Create; Encoder := TBase64EncodingStream.Create(Outputstream); try jpg.Assign(Image1.Picture.Bitmap); jpg.CompressionQuality:=75; jpg.SaveToStream(imgstream); imgstream.Position:= 0; //the following line throws an exception: wrong typecast. //But typecast is not required. //Encoder.CopyFrom(TStringStream(imgstream), imgstream.Size); Encoder.CopyFrom(imgstream, imstream.size); Encoder.Flush; Memo1.Text:='data:image/jpg;base64,'+ TStringStream(Outputstream).DataString; ShowMessage('Created in '+IntToStr(GetTickCount64-I)+'ms'); finally imgstream.Free; Encoder.Free; Outputstream.Free; jpg.Free; end;end;
This works. So, with my limited knowledge of these formats, I tried to write the reverse code and I'm bombing...
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- Procedure TForm1.btn_decodeClick(Sender: TObject);var imgstream, Inputstream: TStream; //<--- this line was cut off during the copy and paste. Decoder: TBase64DecodingStream; jpg: TJPEGImage; I: Int64;begin I := GetTickCount64; //First read the memo back into a string stream InputStream := TStringStream.Create(memo1.Text); //Point the decoder to that string stream Decoder := TBase64DecodingStream.Create(InputStream); InputStream.Position := 0; //Next create the jpg image. jpg := TJPEGImage.Create; //Not sure this line is required? jpg.CompressionQuality := 75; try //If the decoder is working the right way, then it should decode the string back into //a jpg image, no? If so, I should be able to load it into the jpg image but I'm missing //something. jpg.LoadFromStream(Decoder, Decoder.Size); //<--- This lines bomb: wrong format //Now back assign the jpg image into a TImage Image2.Assign(jpg); ShowMessage('Created in ' + IntToStr(GetTickCount64-i) + 'ms'); Finally decoder.free; inputstream.free; jpg.free; End;end;
eljo:
--- Quote from: EganSolo on May 03, 2023, 08:22:49 am ---I want a bit of code that can encode and decode a TImage into a string. I created a simple program with two TImage components, a memo and two buttons: btn_Encode which encodes the content of image1 into a string displayed into the memo and btn_decode which is supposed to take the string in the memo and decode it back into an image to be displayed into Image2 but I've got a bug in that return leg (please see below)
The encoding process, I took from this topic https://stackoverflow.com/questions/57481399/lazarus-timage-to-base64 on Stackoverflow with a minor modification.
--- Quote ---
TBase64EncodingStream is not suitable for big binary conversion, I mean, it will be very slow, also Image1.Picture.SaveToStream, by default, will save the picture as Bitmap format, so it will be very big. Try using JPG format.
--- End quote ---
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.Button1Click(Sender: TObject);var imgstream, Outputstream: TStream; Encoder: TBase64EncodingStream; jpg: TJPEGImage; I: Int64;begin I := GetTickCount64; imgstream := TMemoryStream.Create(); Outputstream := TStringStream.Create(''); jpg := TJPEGImage.Create; Encoder := TBase64EncodingStream.Create(Outputstream); try jpg.Assign(Image1.Picture.Bitmap); jpg.CompressionQuality:=75; jpg.SaveToStream(imgstream); imgstream.Position:= 0; //the following line throws an exception: wrong typecast. //But typecast is not required. //Encoder.CopyFrom(TStringStream(imgstream), imgstream.Size); Encoder.CopyFrom(imgstream, imstream.size); Encoder.Flush; Memo1.Text:='data:image/jpg;base64,'+ TStringStream(Outputstream).DataString; ShowMessage('Created in '+IntToStr(GetTickCount64-I)+'ms'); finally imgstream.Free; Encoder.Free; Outputstream.Free; jpg.Free; end;end;
This works. So, with my limited knowledge of these formats, I tried to write the reverse code and I'm bombing...
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- Procedure TForm1.btn_decodeClick(Sender: TObject);var Decoder: TBase64DecodingStream; jpg: TJPEGImage; I: Int64;begin I := GetTickCount64; //First read the memo back into a string stream InputStream := TStringStream.Create(memo1.Text); //Point the decoder to that string stream Decoder := TBase64DecodingStream.Create(InputStream); InputStream.Position := 0; //Next create the jpg image. jpg := TJPEGImage.Create; //Not sure this line is required? jpg.CompressionQuality := 75; try //If the decoder is working the right way, then it should decode the string back into //a jpg image, no? If so, I should be able to load it into the jpg image but I'm missing //something. jpg.LoadFromStream(Decoder, Decoder.Size); //<--- This lines bomb: wrong format //Now back assign the jpg image into a TImage Image2.Assign(jpg); ShowMessage('Created in ' + IntToStr(GetTickCount64-i) + 'ms'); Finally decoder.free; inputstream.free; jpg.free; End;end;
--- End quote ---
Please provide an accurate copy of your code, on the code provided the InputStream is not defined in the decode click it should bomb a lot earlier unless there is a global variable inputstream somewhere else in your code. Better yet zip a project that demonstrates the problem and attach it to a message.
paweld:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.Button1Click(Sender: TObject);var InputStream, OutputStream: TStringStream; Encoder: TBase64EncodingStream; jpg: TJPEGImage; I: Int64;begin I := GetTickCount64; InputStream := TStringStream.Create; OutputStream := TStringStream.Create; jpg := TJPEGImage.Create; Encoder := TBase64EncodingStream.Create(OutputStream); try jpg.Assign(Image1.Picture.Bitmap); jpg.CompressionQuality := 75; jpg.SaveToStream(InputStream); Encoder.CopyFrom(InputStream, 0); Encoder.Flush; Memo1.Lines.Text := 'data:image/jpg;base64,' + OutputStream.DataString; ShowMessage('Created in ' + IntToStr(GetTickCount64 - I) + 'ms'); finally InputStream.Free; OutputStream.Free; Encoder.Free; jpg.Free; end;end; procedure TForm1.Button2Click(Sender: TObject);var InputStream, OutputStream: TStringStream; s: String; Decoder: TBase64DecodingStream; jpg: TJPEGImage; I: Int64;begin I := GetTickCount64; //First read the memo back into a string stream //with remove mime type info s := Memo1.Lines.Text; if pos(',', s) > 1 then Delete(s, 1, pos(',', s)); InputStream := TStringStream.Create(s); InputStream.Position := 0; OutputStream := TStringStream.Create; //Point the Decoder to that string stream Decoder := TBase64DecodingStream.Create(InputStream); //Next create the jpg image. jpg := TJPEGImage.Create; try OutputStream.CopyFrom(Decoder, Decoder.Size); OutputStream.Position := 0; jpg.LoadFromStream(OutputStream); //Now back assign the jpg image into a TImage Image2.Picture.Assign(jpg); ShowMessage('Created in ' + IntToStr(GetTickCount64 - i) + 'ms'); finally InputStream.Free; OutputStream.Free; Decoder.Free; jpg.Free; end;end;
marcov:
jpg runs compression, which is probably slower than encoding as string.
But possibly the slowest is putting very large blocks of text in a memo. Benchmark before the memo.
Navigation
[0] Message Index