Recent

Author Topic: (SOLVED) Unit Resize image error  (Read 4622 times)

xinyiman

  • Hero Member
  • *****
  • Posts: 2256
    • Lazarus and Free Pascal italian community
(SOLVED) Unit Resize image error
« on: July 24, 2012, 08:10:17 am »
Hello guys I know who explain why the following code in linux and windows not working properly? I do not understand this function should reduce the image passed.

 Alternatively if anyone has some code that does the same job that runs on both windows and linux that it could post?


Why this unit generate error in windows?! (correctly run in linux)
Code: [Select]

unit RidimensionareImmagini;

{$mode objfpc}{$H+}

interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls;

procedure GenerarMini(var MioStream: TStream; mode:integer; Altezza: integer; Larghezza: integer; NomeFileAppoggio: string);

implementation

uses unit1;

procedure GenerarMini(var MioStream: TStream; mode:integer; Altezza: integer; Larghezza: integer; NomeFileAppoggio: string);
var
  jpg1, jpg2: TJPEGImage;
  nf, nf2:    string;

  esX, esY: double;
  an, al, X, Y: integer;
  swOk: boolean;

begin
  try
  try


  jpg1 := TJPEGImage.Create;
  jpg2 := TJPEGImage.Create;

  jpg2.SetSize(Larghezza, Altezza);

  If FileExists(NomeFileAppoggio) Then
    DeleteFile(NomeFileAppoggio);


  nf2 := NomeFileAppoggio;
  try
    swOk := True;
    jpg1.LoadFromStream(MioStream);
  except
    swOk := False;
  end;

  if swOk then
  begin

    // +---- Calcular la escala para no deformar ------------------------------+
    // +---- Calculating the scale to avoid deforming -------------------------+
    an := jpg2.width;
    al  := jpg2.height;

    esX := an / jpg1.Width;
    esY := al / jpg1.Height;

    // +---- Solo se escala el lado que sea necesario -------------------------+
    if esX > esY then
      an := trunc(jpg1.Width * esY + 0.5)
    else
      al := trunc(jpg1.Height * esX + 0.5);

    case mode of
      1:begin
        // +----- Fijo a 120x90, centrando --------------------------------------+
        // +----- Fixed 120x90, centering ---------------------------------------+
        //X:=(120-an) div 2; Y:=(90-al) div 2; // Centrar
        X:=(Larghezza-an) div 2; Y:=(Altezza-al) div 2; // Centrar
        jpg2.Canvas.StretchDraw(Rect(X, Y, X+an, Y+al), jpg1);
      end;
      2: begin
        // +----- Respetando el tamaño -----------------------------------------+
        // +----- keeping the ratio -----------------------------------------------+
        jpg2.SetSize(an, al);
        jpg2.Canvas.StretchDraw(Rect(0, 0, an, al), jpg1);
      end;
    end;
    jpg2.CompressionQuality := 90;  // Or whatever you want.
    jpg2.SaveToFile(nf2);
  end;

  MioStream.Destroy;
  MioStream:=TFileStream.Create(NomeFileAppoggio, fmOpenRead);
  MioStream.Position := 0;

  jpg1.Free;
  jpg2.Free;

  If FileExists(NomeFileAppoggio) Then
    DeleteFile(NomeFileAppoggio);

  finally
  end;
except
     on E: Exception do
     begin
          ShowMessage(E.Message);
     end;
end;
end;

end.



Test code:

Code: [Select]
procedure TForm3.Button1Click(Sender: TObject);
var
   FileStream: TFileStream;
begin
     Form1.AltezzaDaRidimensionare:=Spin_Altezza.Value;
     Form1.LarghezzaDaRidimensionare:=Spin_Larghezza.Value;
     {ora mi sono recuperato le dimensioni che mi interessano}
     If FileExists(application.Location + 'temp.jpg') then
        DeleteFile(application.Location + 'temp.jpg');

     Form1.Img_Rimpicciolita.Picture.SaveToFile(application.Location + 'temp.jpg');

     FileStream := TFileStream.Create(application.Location + 'temp.jpg', fmOpenRead);
     GenerarMini(FileStream, 1, Form1.AltezzaDaRidimensionare , Form1.LarghezzaDaRidimensionare, Application.Location + 'temp.jpg');
     Form1.Img_Rimpicciolita.Picture.LoadFromStream(FileStream);
     FileStream.Destroy;
     If FileExists(application.Location + 'temp.jpg') then
        DeleteFile(application.Location + 'temp.jpg');
     Close;
end;


Errors:

1#: Unable to create file 'c:\softwareP\temp.jpg'

2#: Stream read error
« Last Edit: July 24, 2012, 08:23:52 am by xinyiman »
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

xinyiman

  • Hero Member
  • *****
  • Posts: 2256
    • Lazarus and Free Pascal italian community
Re: Unit Resize image error
« Reply #1 on: July 24, 2012, 08:23:26 am »
Solved with this code

GenerarMini(FileStream, 1, Form1.AltezzaDaRidimensionare , Form1.LarghezzaDaRidimensionare, Application.Location + 'temp1.jpg');
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: (SOLVED) Unit Resize image error
« Reply #2 on: July 24, 2012, 02:12:11 pm »
Ciao Xinyiman,

So instead of telling it to process a file with
Code: [Select]
Application.Location + 'temp.jpg'
you're specifying
Code: [Select]
Application.Location + 'temp1.jpg'
?

Note: you could run into permission issues, e.g. on Windows if you install the application under admin e.g. in c:\program files\yourapplication, you don't have write access to that directory as a normal user (and on Vista and higher, IIRC even as an admin user unless you request elevated privileges from UAC).
IIRC, Windows Vista+ with UAC has some "file overlay" system that transparently redirects these write operations for legacy applications into some directory that is writable by users, but it's a stopgap solution.

On Linux/Unix/OSX, if your application is installed by e.g. root under a directory that normal users don't have write access to (which is normally everything except ~ and some other less relevant ones), you'll have similar problems.

Solutions:
- storing read-only unchanging data files in the application directory is fine. On Linux, IIRC, you might need to place large files somewhere in /var. No idea about OSX.
- use the temp directory for temporary files (GetTempDirectory/GetTempFileName etc). For added security you can specify you want to use the user temp directory instead of the global temp directory
- store user-specific data generated by the application where they belong (e.g. using fileutil.GetAppConfigDirUTF8/sysutils.GetAppConfigDir/fileutil.GetAppConfigFileUTF8/sysutils.GetAppConfigFile; set the Global parameter to false)
- store application wide configuration/data generated by the application where they belong (e.g. using fileutil.GetAppConfigDirUTF8/sysutils.GetAppConfigDir/fileutil.GetAppConfigFileUTF8/sysutils.GetAppConfigFile; set the Global parameter to true)

I think there are some wiki pages (on multiplatform programming) that illustrate this.

Regarding what your code actually does: does it generate a thumbnail jpg or something? Don't know much about graphics programming, suppose it looks reasonable, especially if you don't wnat to use external libraries.
I would clean up the code indentation though...

PS: Code with Italian variable names, and Spanish and English comments... very... international ;)
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

 

TinyPortal © 2005-2018