From 186575dcebc4d8a270af887631a4f29b249cb35b Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 22:46:53 +0200 Subject: [PATCH 1/8] Change libjpegturbo to pkg-config, add tests for libjpegturbo --- .github/workflows/libjpegturbo.yml | 52 ++++++++ .../image/image_jpeg/image_jpeg_go.jpeg.go | 4 +- .../image_jpeg/image_jpeg_go_jpeg_test.go | 38 ++++++ .../image/image_jpeg/image_jpeg_turbojpeg.go | 120 +++++++++++++++++- .../image_jpeg/image_jpeg_turbojpeg_test.go | 55 ++++++++ internal/image/image_jpeg/options.go | 8 ++ internal/implementation_cgo/render.go | 11 +- internal/implementation_webassembly/render.go | 11 +- 8 files changed, 282 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/libjpegturbo.yml create mode 100644 internal/image/image_jpeg/image_jpeg_go_jpeg_test.go create mode 100644 internal/image/image_jpeg/image_jpeg_turbojpeg_test.go create mode 100644 internal/image/image_jpeg/options.go diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml new file mode 100644 index 00000000..a20e8bf9 --- /dev/null +++ b/.github/workflows/libjpegturbo.yml @@ -0,0 +1,52 @@ +name: Go + +on: + push: + branches: + - main + - development + pull_request: + branches: + - main + - development + +jobs: + test-libjpegturbo: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + go: [ "1.19", "1.20", "1.21" ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go }} + + - name: Set up libturbojpeg library (Linux) + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt install libturbojpeg libturbojpeg-dev + + - name: Set up jpeg-turbo library (MacOS) + if: matrix.os == 'macos-latest' + run: | + brew install jpeg-turbo + + - name: Set up jpeg-turbo library (Windows) + if: matrix.os == 'windows-latest' + run: | + curl -L https://master.dl.sourceforge.net/project/libjpeg-turbo/3.0.0/libjpeg-turbo-3.0.0-gcc64.exe -o libjpeg-turbo-3.0.0-gcc64.exe + ./libjpeg-turbo-3.0.0-gcc64.exe /S + + - uses: GuillaumeFalourd/wait-sleep-action@v1 + name: Wait for jpeg-turbo silent install + with: + time: '60' + + - name: Test package + run: | + go test ./internal/image/image_jpeg -tags pdfium_use_turbojpeg -v diff --git a/internal/image/image_jpeg/image_jpeg_go.jpeg.go b/internal/image/image_jpeg/image_jpeg_go.jpeg.go index 018e42ff..789e7a35 100644 --- a/internal/image/image_jpeg/image_jpeg_go.jpeg.go +++ b/internal/image/image_jpeg/image_jpeg_go.jpeg.go @@ -8,6 +8,6 @@ import ( "io" ) -func Encode(w io.Writer, m *image.RGBA, o *jpeg.Options) error { - return jpeg.Encode(w, m, o) +func Encode(w io.Writer, m *image.RGBA, o Options) error { + return jpeg.Encode(w, m, o.Options) } diff --git a/internal/image/image_jpeg/image_jpeg_go_jpeg_test.go b/internal/image/image_jpeg/image_jpeg_go_jpeg_test.go new file mode 100644 index 00000000..f634f74b --- /dev/null +++ b/internal/image/image_jpeg/image_jpeg_go_jpeg_test.go @@ -0,0 +1,38 @@ +//go:build !pdfium_use_turbojpeg + +package image_jpeg + +import ( + "bytes" + "image" + "image/jpeg" + "testing" +) + +func TestEncode(t *testing.T) { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{100, 100}}) + testWriter := bytes.NewBuffer(nil) + err := Encode(testWriter, img, Options{}) + if err != nil { + t.Fatalf("Encode resulted in error: %s", err.Error()) + } + if testWriter.Len() != 789 { + t.Fatalf("Encode resulted in wrong byte result, got %d, want %d", testWriter.Len(), 789) + } +} + +func TestEncodeQuality(t *testing.T) { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{100, 100}}) + testWriter := bytes.NewBuffer(nil) + err := Encode(testWriter, img, Options{ + Options: &jpeg.Options{ + Quality: 100, + }, + }) + if err != nil { + t.Fatalf("Encode resulted in error: %s", err.Error()) + } + if testWriter.Len() != 791 { + t.Fatalf("Encode resulted in wrong byte result, got %d, want %d", testWriter.Len(), 791) + } +} diff --git a/internal/image/image_jpeg/image_jpeg_turbojpeg.go b/internal/image/image_jpeg/image_jpeg_turbojpeg.go index 60091cba..62d5653d 100644 --- a/internal/image/image_jpeg/image_jpeg_turbojpeg.go +++ b/internal/image/image_jpeg/image_jpeg_turbojpeg.go @@ -7,17 +7,118 @@ import ( "image" "image/jpeg" "io" + "unsafe" +) + +/* +#cgo pkg-config: libturbojpeg +#include +*/ +import "C" +import "fmt" + +type Sampling C.int + +const ( + Sampling444 Sampling = C.TJSAMP_444 + Sampling422 Sampling = C.TJSAMP_422 + Sampling420 Sampling = C.TJSAMP_420 + SamplingGray Sampling = C.TJSAMP_GRAY +) + +type PixelFormat C.int - "github.com/bmharper/turbo" +const ( + PixelFormatRGB PixelFormat = C.TJPF_RGB + PixelFormatBGR PixelFormat = C.TJPF_BGR + PixelFormatRGBX PixelFormat = C.TJPF_RGBX + PixelFormatBGRX PixelFormat = C.TJPF_BGRX + PixelFormatXBGR PixelFormat = C.TJPF_XBGR + PixelFormatXRGB PixelFormat = C.TJPF_XRGB + PixelFormatGRAY PixelFormat = C.TJPF_GRAY + PixelFormatRGBA PixelFormat = C.TJPF_RGBA + PixelFormatBGRA PixelFormat = C.TJPF_BGRA + PixelFormatABGR PixelFormat = C.TJPF_ABGR + PixelFormatARGB PixelFormat = C.TJPF_ARGB + PixelFormatCMYK PixelFormat = C.TJPF_CMYK + PixelFormatUNKNOWN PixelFormat = C.TJPF_UNKNOWN ) -func Encode(w io.Writer, m *image.RGBA, o *jpeg.Options) error { +type Flags C.int + +const ( + FlagAccurateDCT Flags = C.TJFLAG_ACCURATEDCT + FlagBottomUp Flags = C.TJFLAG_BOTTOMUP + FlagFastDCT Flags = C.TJFLAG_FASTDCT + FlagFastUpsample Flags = C.TJFLAG_FASTUPSAMPLE + FlagNoRealloc Flags = C.TJFLAG_NOREALLOC + FlagProgressive Flags = C.TJFLAG_PROGRESSIVE + FlagStopOnWarning Flags = C.TJFLAG_STOPONWARNING +) + +func makeError(handler C.tjhandle, returnVal C.int) error { + if returnVal == 0 { + return nil + } + str := C.GoString(C.tjGetErrorStr2(handler)) + return fmt.Errorf("turbojpeg error: %v", str) +} + +type Image struct { + Width int + Height int + Stride int + Pixels []byte +} + +type CompressParams struct { + PixelFormat PixelFormat + Sampling Sampling + Quality int // 1 .. 100 + Flags Flags +} + +func MakeCompressParams(pixelFormat PixelFormat, sampling Sampling, quality int, flags Flags) CompressParams { + return CompressParams{ + PixelFormat: pixelFormat, + Sampling: sampling, + Quality: quality, + Flags: flags, + } +} + +func Compress(img *Image, params CompressParams) ([]byte, error) { + encoder := C.tjInitCompress() + defer C.tjDestroy(encoder) + + var outBuf *C.uchar + var outBufSize C.ulong + + // int tjCompress2(tjhandle handle, const unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, + // unsigned char **jpegBuf, unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags); + res := C.tjCompress2(encoder, (*C.uchar)(&img.Pixels[0]), C.int(img.Width), C.int(img.Stride), C.int(img.Height), C.int(params.PixelFormat), + &outBuf, &outBufSize, C.int(params.Sampling), C.int(params.Quality), C.int(params.Flags)) + + var enc []byte + err := makeError(encoder, res) + if outBuf != nil { + enc = C.GoBytes(unsafe.Pointer(outBuf), C.int(outBufSize)) + C.tjFree(outBuf) + } + + if err != nil { + return nil, err + } + return enc, nil +} + +func Encode(w io.Writer, m *image.RGBA, o Options) error { imageWriter := bufio.NewWriter(w) // Clip quality to [1, 100]. quality := jpeg.DefaultQuality - if o != nil { - quality = o.Quality + if o.Options != nil { + quality = o.Options.Quality if quality < 1 { quality = 1 } else if quality > 100 { @@ -27,15 +128,20 @@ func Encode(w io.Writer, m *image.RGBA, o *jpeg.Options) error { dimensions := m.Bounds().Size() - raw := turbo.Image{ + raw := Image{ Width: dimensions.X, Height: dimensions.Y, Stride: m.Stride, Pixels: m.Pix, } - params := turbo.MakeCompressParams(turbo.PixelFormatRGBA, turbo.Sampling420, quality, 0) - jpg, err := turbo.Compress(&raw, params) + flags := Flags(0) + if o.Progressive { + flags |= FlagProgressive + } + + params := MakeCompressParams(PixelFormatRGBA, Sampling420, quality, flags) + jpg, err := Compress(&raw, params) if err != nil { return err } diff --git a/internal/image/image_jpeg/image_jpeg_turbojpeg_test.go b/internal/image/image_jpeg/image_jpeg_turbojpeg_test.go new file mode 100644 index 00000000..3c96e126 --- /dev/null +++ b/internal/image/image_jpeg/image_jpeg_turbojpeg_test.go @@ -0,0 +1,55 @@ +//go:build pdfium_use_turbojpeg + +package image_jpeg + +import ( + "bytes" + "image" + "image/jpeg" + "testing" +) + +func TestEncode(t *testing.T) { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{100, 100}}) + testWriter := bytes.NewBuffer(nil) + err := Encode(testWriter, img, Options{}) + if err != nil { + t.Fatalf("Encode resulted in error: %s", err.Error()) + } + if testWriter.Len() != 823 { + t.Fatalf("Encode resulted in wrong byte result, got %d, want %d", testWriter.Len(), 823) + } +} + +func TestEncodeQuality(t *testing.T) { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{100, 100}}) + testWriter := bytes.NewBuffer(nil) + err := Encode(testWriter, img, Options{ + Options: &jpeg.Options{ + Quality: 100, + }, + }) + if err != nil { + t.Fatalf("Encode resulted in error: %s", err.Error()) + } + if testWriter.Len() != 825 { + t.Fatalf("Encode resulted in wrong byte result, got %d, want %d", testWriter.Len(), 825) + } +} + +func TestEncodeProgressive(t *testing.T) { + img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{100, 100}}) + testWriter := bytes.NewBuffer(nil) + err := Encode(testWriter, img, Options{ + Options: &jpeg.Options{ + Quality: 100, + }, + Progressive: true, + }) + if err != nil { + t.Fatalf("Encode resulted in error: %s", err.Error()) + } + if testWriter.Len() != 592 { + t.Fatalf("Encode resulted in wrong byte result, got %d, want %d", testWriter.Len(), 592) + } +} diff --git a/internal/image/image_jpeg/options.go b/internal/image/image_jpeg/options.go new file mode 100644 index 00000000..85f43b35 --- /dev/null +++ b/internal/image/image_jpeg/options.go @@ -0,0 +1,8 @@ +package image_jpeg + +import "image/jpeg" + +type Options struct { + *jpeg.Options + Progressive bool // Render in progressive mode, only available with libturbojpeg. +} diff --git a/internal/implementation_cgo/render.go b/internal/implementation_cgo/render.go index 3492b62d..2e1695ea 100644 --- a/internal/implementation_cgo/render.go +++ b/internal/implementation_cgo/render.go @@ -481,11 +481,14 @@ func (p *PdfiumImplementation) RenderToFile(request *requests.RenderToFile) (*re var imgBuf bytes.Buffer if request.OutputFormat == requests.RenderToFileOutputFormatJPG { - var opt jpeg.Options - opt.Quality = 95 + opt := image_jpeg.Options{ + Options: &jpeg.Options{ + Quality: 95, + }, + } if request.OutputQuality > 0 { - opt.Quality = request.OutputQuality + opt.Options.Quality = request.OutputQuality } // If any of the pages have transparency, place a white background under @@ -501,7 +504,7 @@ func (p *PdfiumImplementation) RenderToFile(request *requests.RenderToFile) (*re } for { - err := image_jpeg.Encode(&imgBuf, renderedImage, &opt) + err := image_jpeg.Encode(&imgBuf, renderedImage, opt) if err != nil { return nil, err } diff --git a/internal/implementation_webassembly/render.go b/internal/implementation_webassembly/render.go index 28bbb196..d469c79b 100644 --- a/internal/implementation_webassembly/render.go +++ b/internal/implementation_webassembly/render.go @@ -536,11 +536,14 @@ func (p *PdfiumImplementation) RenderToFile(request *requests.RenderToFile) (*re var imgBuf bytes.Buffer if request.OutputFormat == requests.RenderToFileOutputFormatJPG { - var opt jpeg.Options - opt.Quality = 95 + opt := image_jpeg.Options{ + Options: &jpeg.Options{ + Quality: 95, + }, + } if request.OutputQuality > 0 { - opt.Quality = request.OutputQuality + opt.Options.Quality = request.OutputQuality } // If any of the pages have transparency, place a white background under @@ -556,7 +559,7 @@ func (p *PdfiumImplementation) RenderToFile(request *requests.RenderToFile) (*re } for { - err := image_jpeg.Encode(&imgBuf, renderedImage, &opt) + err := image_jpeg.Encode(&imgBuf, renderedImage, opt) if err != nil { return nil, err } From 4fa81dcfb833b8a75ae47ea4f489827e332f93b5 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 22:59:56 +0200 Subject: [PATCH 2/8] Add progressive option to render, try to fix Windows test --- .github/workflows/libjpegturbo.yml | 14 +++++++++++--- internal/implementation_cgo/render.go | 1 + requests/render.go | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index a20e8bf9..a1129fa7 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -1,4 +1,4 @@ -name: Go +name: lib-jpeg-turbo on: push: @@ -43,10 +43,18 @@ jobs: ./libjpeg-turbo-3.0.0-gcc64.exe /S - uses: GuillaumeFalourd/wait-sleep-action@v1 - name: Wait for jpeg-turbo silent install + name: Wait for jpeg-turbo silent install (Windows) + if: matrix.os == 'windows-latest' with: time: '60' - - name: Test package + - name: Test package (non-Windows) + if: matrix.os == 'windows-latest' + run: | + go test ./internal/image/image_jpeg -tags pdfium_use_turbojpeg -v + + - name: Test package (Windows) + if: matrix.os == 'windows-latest' run: | + $env:PKG_CONFIG_PATH = 'C:\libjpeg-turbo-gcc64\lib\pkgconfig' go test ./internal/image/image_jpeg -tags pdfium_use_turbojpeg -v diff --git a/internal/implementation_cgo/render.go b/internal/implementation_cgo/render.go index 2e1695ea..06faded9 100644 --- a/internal/implementation_cgo/render.go +++ b/internal/implementation_cgo/render.go @@ -485,6 +485,7 @@ func (p *PdfiumImplementation) RenderToFile(request *requests.RenderToFile) (*re Options: &jpeg.Options{ Quality: 95, }, + Progressive: request.Progressive, } if request.OutputQuality > 0 { diff --git a/requests/render.go b/requests/render.go index e20b0e4c..37e00d90 100644 --- a/requests/render.go +++ b/requests/render.go @@ -49,6 +49,7 @@ type RenderToFile struct { OutputFormat RenderToFileOutputFormat // The format to output the image as OutputTarget RenderToFileOutputTarget // Where to output the image OutputQuality int // Only used when OutputFormat RenderToFileOutputFormatJPG. Ranges from 1 to 100 inclusive, higher is better. The default is 95. + Progressive bool // Only used when OutputFormat RenderToFileOutputFormatJPG and with build tag pdfium_use_turbojpeg. Will render a progressive jpeg. MaxFileSize int64 // The maximum file size, when OutputFormat RenderToFileOutputFormatJPG, it will try to lower the quality it until it fits. TargetFilePath string // When OutputTarget is file, the path to write it to, if not given, a temp file is created } From 9fa8fdce92786e38ffedaa6e6a8c5476651ed357 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 23:03:24 +0200 Subject: [PATCH 3/8] Proper if condition --- .github/workflows/libjpegturbo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index a1129fa7..1d8a2469 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -49,7 +49,7 @@ jobs: time: '60' - name: Test package (non-Windows) - if: matrix.os == 'windows-latest' + if: matrix.os != 'windows-latest' run: | go test ./internal/image/image_jpeg -tags pdfium_use_turbojpeg -v From eda79f0152f63d76deb06eac7c722563886cbd44 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 23:10:59 +0200 Subject: [PATCH 4/8] Increase timeout for windows --- .github/workflows/libjpegturbo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index 1d8a2469..372c1ec5 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -46,7 +46,7 @@ jobs: name: Wait for jpeg-turbo silent install (Windows) if: matrix.os == 'windows-latest' with: - time: '60' + time: '120' - name: Test package (non-Windows) if: matrix.os != 'windows-latest' From 029c1b9d6fab35b5192739647b3ec3e279a2f6f0 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 23:16:56 +0200 Subject: [PATCH 5/8] Remove go 1.19 test due to broken Windows install --- .github/workflows/go.yml | 2 +- .github/workflows/libjpegturbo.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index a298ef36..a780751c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - go: [ "1.19", "1.20", "1.21" ] + go: [ "1.20", "1.21" ] pdfium: [ "4849", "6015" ] env: PDFIUM_EXPERIMENTAL_VERSION: "6015" diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index 372c1ec5..c7fd567b 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - go: [ "1.19", "1.20", "1.21" ] + go: [ "1.20", "1.21" ] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 From a137c4f5944b797cc42c534ccbe2917a346c8977 Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 23:30:45 +0200 Subject: [PATCH 6/8] Check for folder --- .github/workflows/libjpegturbo.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index c7fd567b..7dbf61e0 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -41,12 +41,10 @@ jobs: run: | curl -L https://master.dl.sourceforge.net/project/libjpeg-turbo/3.0.0/libjpeg-turbo-3.0.0-gcc64.exe -o libjpeg-turbo-3.0.0-gcc64.exe ./libjpeg-turbo-3.0.0-gcc64.exe /S - - - uses: GuillaumeFalourd/wait-sleep-action@v1 - name: Wait for jpeg-turbo silent install (Windows) - if: matrix.os == 'windows-latest' - with: - time: '120' + until [[ -d "C:\libjpeg-turbo-gcc64\lib\pkgconfig" ]] + do + echo "exists" + done - name: Test package (non-Windows) if: matrix.os != 'windows-latest' From 02ae3a303c862d8dd5adf72d392e00376a37e60c Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 23:33:54 +0200 Subject: [PATCH 7/8] Powershell check --- .github/workflows/libjpegturbo.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index 7dbf61e0..a1a137f8 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -41,10 +41,10 @@ jobs: run: | curl -L https://master.dl.sourceforge.net/project/libjpeg-turbo/3.0.0/libjpeg-turbo-3.0.0-gcc64.exe -o libjpeg-turbo-3.0.0-gcc64.exe ./libjpeg-turbo-3.0.0-gcc64.exe /S - until [[ -d "C:\libjpeg-turbo-gcc64\lib\pkgconfig" ]] - do - echo "exists" - done + $Folder = 'C:\libjpeg-turbo-gcc64\lib\pkgconfig' + if (Test-Path -Path $Folder) { + "Path exists!" + } - name: Test package (non-Windows) if: matrix.os != 'windows-latest' From d422617c19097f833afe6c4ea642e9271d5c08ac Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Thu, 28 Sep 2023 23:37:47 +0200 Subject: [PATCH 8/8] Properly sleep --- .github/workflows/libjpegturbo.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/libjpegturbo.yml b/.github/workflows/libjpegturbo.yml index a1a137f8..82ca74a9 100644 --- a/.github/workflows/libjpegturbo.yml +++ b/.github/workflows/libjpegturbo.yml @@ -42,8 +42,9 @@ jobs: curl -L https://master.dl.sourceforge.net/project/libjpeg-turbo/3.0.0/libjpeg-turbo-3.0.0-gcc64.exe -o libjpeg-turbo-3.0.0-gcc64.exe ./libjpeg-turbo-3.0.0-gcc64.exe /S $Folder = 'C:\libjpeg-turbo-gcc64\lib\pkgconfig' - if (Test-Path -Path $Folder) { - "Path exists!" + while (!(Test-Path -Path $Folder)) { + "libjpeg-turbo does not exist yet!" + Start-Sleep -s 5 } - name: Test package (non-Windows)