Page 1 of 1

Problem with RunProgram() and quotes

Posted: Sun Apr 03, 2022 9:17 pm
by Lebostein
I want to overwrite a comment of an image with exiftool:

Code: Select all

/usr/local/bin/exiftool -overwrite_original -comment="This is a test" image.jpg
with Purebasic this don't work:

Code: Select all

prog$ = "/usr/local/bin/exiftool"
para$ = "-overwrite_original -comment=" + #DQUOTE$ + "This is a test" + #DQUOTE$ + " image.jpg"
RunProgram(prog$, para$, "") ; dont work, the image comment is only "This"
Debug prog$ + " " + para$ ; past and run on command line, works

Re: Problem with RunProgram() and quotes

Posted: Mon Apr 04, 2022 6:32 pm
by infratec
The best way to test this stuff is to write a program in PB which prints the received parameters:

Code: Select all

OpenConsole()
For i = 0 To CountProgramParameters() - 1
  PrintN(Str(i) + ": " + ProgramParameter(i))
Next i
CloseConsole()
Compile it as console program and call it instead of exif.

Re: Problem with RunProgram() and quotes

Posted: Mon Apr 04, 2022 10:10 pm
by AZJIO

Code: Select all

prog$="bash"
https://www.purebasic.fr/english/search ... mit=Search

infratec
The exiftool utility can interpret parameters in its own way, not like PureBasic

It is not clear what is the real path to the working directory. For a terminal, this is the home directory, while for code in the compiler, this may be the tmp folder.

Code: Select all

SetCurrentDirectory(GetHomeDirectory())

Re: Problem with RunProgram() and quotes

Posted: Tue Apr 05, 2022 7:05 am
by infratec
AZJIO wrote: Mon Apr 04, 2022 10:10 pm The exiftool utility can interpret parameters in its own way, not like PureBasic
I don' interprete the parameters with my code. I simply show the parameters how they arrive.
And this way is for all executables the same.

Re: Problem with RunProgram() and quotes

Posted: Tue Apr 05, 2022 8:42 am
by Marc56us
Hi Lebostein,

This doesn't directly answer the question, but if you want to read or write a JPG comment, you can do so with a few lines of PB. So you can make your own command line tool that will only take 25kb instead of the 8.4MB of exiftool.
Yes, libs exist, but it's often more stimulating to (re)make it yourself.

The comment is written at the beginning of the file, search tags ($FF then $FE). The file does not need to be recompressed after modification.

Structure header: https://en.wikipedia.org/wiki/JPEG#Syntax_and_structure

Comment is set with:
1. Marker: $FF (tag of field)
2. Marker: $FE (Comment)
3. Size of comment (2 bytes, indianless)
4. Comment (Utf-8 fill with $00) max 64k
5. Next $FF

Basic method (without using any lib: Yes PB do all)

Read comment:
Search for $FF then $FE, read size (2 next bytes), read comment (with size or until found \0)
(This is a null-terminated string, so no need to read size: read with ReadString will stop at first \0)

Write comment:
1. Search if comment still exist (if exist, overwrite size and text. Use Loc to keep read position if comment exist)
2. Open New file for writing
3. Read block from source file until $FF
4. Write this block to destination file
5. Write $FF, $FE
6. Write Size of new string
7. Write (new) comment
8. Read rest of source file and write it to destination file
9. Close Source file and destination file (keep source as backup, like Exifttool do or delete if)

Keywords
- ReadFile, ReadByte, FileSeek, Loc, CreateFile, ReadData, WriteData, WriteCharacter, WriteByte, WriteString, CloseFile
you can probably also do it with Peek, Poke and pointer, but I still don't understand much about it, so I stay with the classic functions (read, write, fileseek)

Example of reading (only simples PB functions)

Code: Select all

EnableExplicit
If ReadFile(0, "image.jpg")
    While Not Eof(0)
        If ReadCharacter(0) = $FEFF         ; Search comment tag 
            FileSeek(0, 1, #PB_Relative) 
            MessageRequester("Comment", 
                             ReadString(0, #PB_UTF8, ReadByte(0) -2), 
                             #PB_MessageRequester_Info)
            Break
        EndIf
    Wend
    CloseFile(0)
Else
    MessageRequester("Error", "File Not Found", #PB_MessageRequester_Error)
EndIf
Enjoy
:wink:

Re: Problem with RunProgram() and quotes

Posted: Wed Apr 06, 2022 8:59 am
by Lebostein
AZJIO wrote: Mon Apr 04, 2022 10:10 pm

Code: Select all

prog$="bash"
https://www.purebasic.fr/english/search ... mit=Search

infratec
The exiftool utility can interpret parameters in its own way, not like PureBasic

It is not clear what is the real path to the working directory. For a terminal, this is the home directory, while for code in the compiler, this may be the tmp folder.

Code: Select all

SetCurrentDirectory(GetHomeDirectory())
You mean I should use "bash" for the program parameter and the executable of the program is the first parameter??? This contradicts the PB-manual... Would this then apply to all command line programs on Mac or is this specifically only about exiftool?

Re: Problem with RunProgram() and quotes

Posted: Wed Apr 06, 2022 9:01 am
by AZJIO
Lebostein wrote: Wed Apr 06, 2022 8:59 amYou mean I should use "bash" for the program parameter and the executable of the program is the first parameter???
Yes. If it works in the terminal, try running through the terminal.

Re: Problem with RunProgram() and quotes

Posted: Wed Apr 06, 2022 9:04 am
by Lebostein
AZJIO wrote: Wed Apr 06, 2022 9:01 am
Lebostein wrote: Wed Apr 06, 2022 8:59 amYou mean I should use "bash" for the program parameter and the executable of the program is the first parameter???
Yes. If it works in the terminal, try running through the terminal.
Thanks. But why this very important thing is not noted in the PureBasic manual?

Re: Problem with RunProgram() and quotes

Posted: Wed Apr 06, 2022 9:35 am
by Marc56us
Thanks. But why this very important thing is not noted in the PureBasic manual?
Because it is specific to certain commands on un*x systems (MacOS is BSD based, so un*x))
For exiftool, the Windows version is a compiled executable. (so RunProgram("exiftool", "parameters"... works)
The Unix and Mac version of exiftool are scripts (perl) encapsulated or not with the perl runtime if it is already present or not.
See details on https://exiftool.org/install.html
As these two versions are scripts, they must be launched in/by a shell (bash, sh, zsh, ksh etc)
I don't have a mac, but I see that linux version have a shebang in main script (#!/usr/bin/perl -w). I thing RunProgram not read this line, but shell (bash) do it.
If you are in a terminal, the shell is already open. (compile as Console Mode, RunProgram("exiftool", "...) will works.
If you run the script directly, then you have to open a shell first. RunProgram("sh", "exiftool ...")
(It is like a 'cmd', "/c ..." under Windows)
Note: to ensure compatibility in programs, it is better to use 'sh' rather than 'bash'.
'sh' is a symbolic link to the shell defined for the user. The command line will automatically adapt to whatever shell the user is using.
You can put 'sh' in any case, but this will have the effect of opening a shell in a shell, thus losing ram and the environment variables of the first shell