diff --git a/.all-contributorsrc b/.all-contributorsrc
index 95122bc1fd..9beea4235e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1733,6 +1733,15 @@
"contributions": [
"bug"
]
+ },
+ {
+ "login": "kjhollen",
+ "name": "Kate Hollenbach",
+ "avatar_url": "https://avatars.githubusercontent.com/u/78966?v=4",
+ "profile": "https://github.com/kjhollen",
+ "contributions": [
+ "bug"
+ ]
}
],
"repoType": "github",
@@ -1740,4 +1749,4 @@
"skipCi": true,
"commitConvention": "angular",
"commitType": "docs"
-}
+}
\ No newline at end of file
diff --git a/.github/workflows/contributors-png.yml b/.github/workflows/contributors-png.yml
new file mode 100644
index 0000000000..040bfe7256
--- /dev/null
+++ b/.github/workflows/contributors-png.yml
@@ -0,0 +1,40 @@
+name: Generate Contributors PNG
+
+on:
+ push:
+ paths:
+ - '.all-contributorsrc'
+
+jobs:
+ genimage:
+ if: github.ref == 'refs/heads/main' && github.repository == 'processing/processing4'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Install dependencies
+ run: npm install canvas
+
+ - name: Run contributors-png generator
+ run: node utils/contributors-png.js
+
+ - name: Reset all changes except contributors.png
+ run: |
+ git restore --staged .
+ git add contributors.png
+ git checkout -- .
+
+ - name: Create Pull Request
+ uses: peter-evans/create-pull-request@v7
+ with:
+ commit-message: "Update contributors.png from .all-contributorsrc"
+ branch: update-contributors-png
+ title: "chore: update contributors.png from .all-contributorsrc"
+ body: "This PR updates the contributors.png to reflect changes in .all-contributorsrc"
+ add-paths: contributors.png
+ token: ${{ secrets.CONTRIBUTOR_PNG_ACCESS_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e21fce7a40..b41c7d62e3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,7 +1,8 @@
name: Releases
on:
- release:
- types: [published]
+ push:
+ tags:
+ - 'processing-*'
jobs:
version:
@@ -21,12 +22,36 @@ jobs:
# Set outputs for use in later jobs or steps
echo "revision=$REVISION" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
+
+ create-draft:
+ name: Create draft release
+ runs-on: ubuntu-latest
+ needs: version
+ permissions:
+ contents: write
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GH_REPO: ${{ github.repository }}
+ TAG: ${{ github.ref_name }}
+ VERSION: ${{ needs.version.outputs.version }}
+ steps:
+ - name: Create draft release
+ run: |
+ if gh release view "$TAG" >/dev/null 2>&1; then
+ echo "Release for $TAG already exists; leaving it as-is."
+ else
+ gh release create "$TAG" \
+ --draft \
+ --title "Processing $VERSION" \
+ --generate-notes
+ fi
+
reference:
name: Publish Processing Reference to release
runs-on: ubuntu-latest
permissions:
contents: write
- needs: version
+ needs: [version, create-draft]
steps:
- name: Checkout Website Repository
uses: actions/checkout@v4
@@ -42,17 +67,23 @@ jobs:
run: npm run build
- name: Make reference.zip
run: npm run zip
+ - name: Stage reference asset
+ env:
+ VERSION: ${{ needs.version.outputs.version }}
+ run: |
+ mkdir -p release-assets
+ cp reference.zip "release-assets/processing-${VERSION}-reference.zip"
- name: Upload reference to release
- uses: svenstaro/upload-release-action@v2
+ uses: softprops/action-gh-release@v2
with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-reference.zip
- file: reference.zip
+ draft: true
+ tag_name: ${{ github.ref_name }}
+ files: release-assets/processing-${{ needs.version.outputs.version }}-reference.zip
publish-maven:
name: Publish Processing Libraries to Maven Central
runs-on: ubuntu-latest
- needs: version
+ needs: [version, release-windows, release-macos, release-linux]
steps:
- name: Checkout Repository
uses: actions/checkout@v4
@@ -78,7 +109,7 @@ jobs:
publish-gradle:
name: Publish Processing Plugins to Gradle Plugin Portal
runs-on: ubuntu-latest
- needs: version
+ needs: [version, release-windows, release-macos, release-linux]
steps:
- name: Checkout Repository
uses: actions/checkout@v4
@@ -97,7 +128,7 @@ jobs:
ORG_GRADLE_PROJECT_version: ${{ needs.version.outputs.version }}
ORG_GRADLE_PROJECT_group: ${{ vars.GRADLE_GROUP }}
-
+
- name: Publish internal plugins to Gradle Plugin Portal
run: ./gradlew -c gradle/plugins/settings.gradle.kts publishPlugins
env:
@@ -114,7 +145,7 @@ jobs:
release-windows:
name: (windows/${{ matrix.arch }}) Create Processing Release
runs-on: ${{ matrix.os }}
- needs: version
+ needs: [version, create-draft]
permissions:
contents: write
strategy:
@@ -154,24 +185,27 @@ jobs:
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- - name: Upload portable version
- uses: svenstaro/upload-release-action@v2
- with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-windows-${{ matrix.arch }}-portable.zip
- file: app/build/compose/binaries/main/Processing-${{ needs.version.outputs.version }}.zip
+ - name: Stage release assets
+ shell: bash
+ env:
+ VERSION: ${{ needs.version.outputs.version }}
+ ARCH: ${{ matrix.arch }}
+ run: |
+ mkdir -p release-assets
+ cp "app/build/compose/binaries/main/Processing-${VERSION}.zip" "release-assets/processing-${VERSION}-windows-${ARCH}-portable.zip"
+ cp "app/build/compose/binaries/main/msi/Processing-${VERSION}.msi" "release-assets/processing-${VERSION}-windows-${ARCH}.msi"
- - name: Upload installer
- uses: svenstaro/upload-release-action@v2
+ - name: Upload release assets
+ uses: softprops/action-gh-release@v2
with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-windows-${{ matrix.arch }}.msi
- file: app/build/compose/binaries/main/msi/Processing-${{ needs.version.outputs.version }}.msi
+ draft: true
+ tag_name: ${{ github.ref_name }}
+ files: release-assets/*
release-macos:
name: (macOS/${{ matrix.arch }}) Create Processing Release
runs-on: macos-latest
- needs: version
+ needs: [version, create-draft]
permissions:
contents: write
strategy:
@@ -209,24 +243,26 @@ jobs:
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.password: ${{ secrets.PROCESSING_APP_PASSWORD }}
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.teamID: ${{ secrets.PROCESSING_TEAM_ID }}
- - name: Upload portables to release
- uses: svenstaro/upload-release-action@v2
- with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-macos-${{ matrix.arch }}-portable.zip
- file: app/build/compose/binaries/main/Processing-${{ needs.version.outputs.version }}.zip
+ - name: Stage release assets
+ env:
+ VERSION: ${{ needs.version.outputs.version }}
+ ARCH: ${{ matrix.arch }}
+ run: |
+ mkdir -p release-assets
+ cp "app/build/compose/binaries/main/Processing-${VERSION}.zip" "release-assets/processing-${VERSION}-macos-${ARCH}-portable.zip"
+ cp "app/build/compose/binaries/main/dmg/Processing-${VERSION}.dmg" "release-assets/processing-${VERSION}-macos-${ARCH}.dmg"
- - name: Upload installers to release
- uses: svenstaro/upload-release-action@v2
+ - name: Upload release assets
+ uses: softprops/action-gh-release@v2
with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-macos-${{ matrix.arch }}.dmg
- file: app/build/compose/binaries/main/dmg/Processing-${{ needs.version.outputs.version }}.dmg
+ draft: true
+ tag_name: ${{ github.ref_name }}
+ files: release-assets/*
release-linux:
name: (linux/${{ matrix.arch }}) Create Processing Release
runs-on: ${{ matrix.os }}
- needs: version
+ needs: [version, create-draft]
permissions:
contents: write
strategy:
@@ -254,19 +290,22 @@ jobs:
ORG_GRADLE_PROJECT_revision: ${{ needs.version.outputs.revision }}
ORG_GRADLE_PROJECT_compose.desktop.verbose: true
- - name: Upload portable to release
- uses: svenstaro/upload-release-action@v2
- with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-linux-${{ matrix.arch }}-portable.zip
- file: app/build/compose/binaries/main/Processing-${{ needs.version.outputs.version }}.zip
+ - name: Stage release assets
+ env:
+ VERSION: ${{ needs.version.outputs.version }}
+ ARCH: ${{ matrix.arch }}
+ DEB: ${{ matrix.deb }}
+ run: |
+ mkdir -p release-assets
+ cp "app/build/compose/binaries/main/Processing-${VERSION}.zip" "release-assets/processing-${VERSION}-linux-${ARCH}-portable.zip"
+ cp "app/build/compose/binaries/main/deb/processing_${VERSION}-1_${DEB}.deb" "release-assets/processing-${VERSION}-linux-${ARCH}.deb"
- - name: Upload installer to release
- uses: svenstaro/upload-release-action@v2
+ - name: Upload release assets
+ uses: softprops/action-gh-release@v2
with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-linux-${{ matrix.arch }}.deb
- file: app/build/compose/binaries/main/deb/processing_${{ needs.version.outputs.version }}-1_${{ matrix.deb }}.deb
+ draft: true
+ tag_name: ${{ github.ref_name }}
+ files: release-assets/*
- name: Add artifact
uses: actions/upload-artifact@v4
@@ -278,7 +317,7 @@ jobs:
release-linux-snap:
name: (linux/${{ matrix.arch }}) Create Processing Snap Release
runs-on: ${{ matrix.os }}
- needs: [version, release-linux]
+ needs: [version, create-draft, release-linux]
permissions:
contents: write
strategy:
@@ -316,12 +355,22 @@ jobs:
ORG_GRADLE_PROJECT_snapname: ${{ vars.SNAP_NAME }}
ORG_GRADLE_PROJECT_snapconfinement: ${{ vars.SNAP_CONFINEMENT }}
+ - name: Stage release assets
+ env:
+ VERSION: ${{ needs.version.outputs.version }}
+ ARCH: ${{ matrix.arch }}
+ DEB: ${{ matrix.deb }}
+ SNAP_NAME: ${{ vars.SNAP_NAME }}
+ run: |
+ mkdir -p release-assets
+ cp "app/build/compose/binaries/main/${SNAP_NAME}_${VERSION}_${DEB}.snap" "release-assets/processing-${VERSION}-linux-${ARCH}.snap"
+
- name: Upload snap to release
- uses: svenstaro/upload-release-action@v2
+ uses: softprops/action-gh-release@v2
with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-linux-${{ matrix.arch }}.snap
- file: app/build/compose/binaries/main/${{ vars.SNAP_NAME }}_${{ needs.version.outputs.version }}_${{ matrix.deb }}.snap
+ draft: true
+ tag_name: ${{ github.ref_name }}
+ files: release-assets/processing-${{ needs.version.outputs.version }}-linux-${{ matrix.arch }}.snap
- name: Upload snap to Snap Store
run: snapcraft upload --release=beta app/build/compose/binaries/main/${{ vars.SNAP_NAME }}_${{ needs.version.outputs.version }}_${{ matrix.deb }}.snap
@@ -330,7 +379,7 @@ jobs:
release-linux-flatpak:
name: (linux/${{ matrix.arch }}) Create Processing Flatpak Release
runs-on: ${{ matrix.os }}
- needs: [ version, release-linux ]
+ needs: [version, create-draft, release-linux]
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48
options: --privileged
@@ -375,9 +424,42 @@ jobs:
cache-key: flatpak-builder-${{ github.sha }}
arch: ${{ matrix.farch }}
+ - name: Stage release assets
+ env:
+ VERSION: ${{ needs.version.outputs.version }}
+ ARCH: ${{ matrix.arch }}
+ run: |
+ mkdir -p release-assets
+ cp processing.flatpak "release-assets/processing-${VERSION}-linux-${ARCH}.flatpak"
+
- name: Upload Flatpak to release
- uses: svenstaro/upload-release-action@v2
+ uses: softprops/action-gh-release@v2
with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- asset_name: processing-${{ needs.version.outputs.version }}-linux-${{ matrix.arch }}.flatpak
- file: processing.flatpak
\ No newline at end of file
+ draft: true
+ tag_name: ${{ github.ref_name }}
+ files: release-assets/processing-${{ needs.version.outputs.version }}-linux-${{ matrix.arch }}.flatpak
+
+ publish-release:
+ name: Publish release
+ runs-on: ubuntu-latest
+ environment: release
+ needs:
+ - version
+ - create-draft
+ - reference
+ - publish-maven
+ - publish-gradle
+ - release-windows
+ - release-macos
+ - release-linux
+ - release-linux-snap
+ - release-linux-flatpak
+ permissions:
+ contents: write
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GH_REPO: ${{ github.repository }}
+ TAG: ${{ github.ref_name }}
+ steps:
+ - name: Mark release as published
+ run: gh release edit "$TAG" --draft=false --latest
diff --git a/BUILD.md b/BUILD.md
index 1216f2e952..9e1fd7e552 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -4,21 +4,25 @@ Great to see you are interested in contributing to Processing. To get started yo
## IntelliJ IDEA (recommended)
-First, [download the IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/). Make sure to select the "Community Edition", not "Ultimate". The Community Edition is free and built on open-source software. You may need to scroll down to find the download link.
+_**Note:** A paid subscription is **not** required. Everything needed to build and work on Processing is available for free in IntelliJ IDEA._
+
+1. [Download IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and install it.
+1. Clone the `Processing4` repository locally.
+1. Open the cloned repository in **IntelliJ IDEA**.
+1. When prompted, select **Trust Project**. (You can preview the project in Safe Mode, but you will not be able to build Processing.)
+1. If IntelliJ asks whether to import the Gradle project, select **Load Gradle Project**.
+1. Make sure IntelliJ and Gradle are both using **JDK 17**:
+ * Go to **`File > Project Structure > Project`**
+ * Set **Project SDK** to **JDK 17** (we recommend **Eclipse Temurin**)
+ * If needed, choose **Download JDK…** and install **Version 17**
+ * Then go to **`Settings > Build, Execution, Deployment > Build Tools > Gradle`**
+ * Set **Gradle JVM** to the same **JDK 17**
+1. Wait for Gradle sync to finish.
+1. Click the green **Run** button in the top right to build and launch Processing. You can also use this menu to start a debug session.
> [!TIP]
> If you encounter any issues with this process, Read the [Troubleshooting and Setup Tips for IntelliJ IDEA](#troubleshooting-and-setup-tips-intellij-idea)
-1. Clone the Processing4 repository to your machine locally
-1. Open the cloned repository in IntelliJ IDEA CE
-1. When prompted, select **Trust Project**. You can preview the project in Safe Mode but you won't be able to build Processing.
-1. IntelliJ may ask if you want to load Gradle project. If you allow this, make sure you are using JDK version 17.
-1. In the main menu, go to File > Project Structure > Project Settings > Project.
-1. In the SDK Dropdown option, select a JDK version 17 or Download the jdk
-1. Click the green Run Icon in the top right of the window. This is also where you can find the option to debug Processing.
-1. Logs can be found in the `Build` or `Debug` pane on the bottom left of the window
-
-
## VSCode
1. Clone the Processing4 repository to your machine locally
1. Open the cloned repository in VScode
@@ -138,23 +142,32 @@ If you’re building Processing using IntelliJ IDEA and something’s not workin
### Use the Correct JDK (temurin-17)
-Make sure IntelliJ is using **temurin-17**, not another version. Some users have reported issues with ms-17.
+Make sure IntelliJ is using **temurin-17**. Some users have reported issues with other distributions.
+
+#### 1. Set the Project SDK
-1. Go to **File > Project Structure > Project**
-2. Set the **Project SDK** to: `temurin-17 java version "17.0.15"`
+1. Go to **`File > Project Structure > Project`**
+1. Set the **`Project SDK`** to **`temurin-17`**

-If it is not already installed, you can download it by:
-1. Clicking the SDK input field and then selecting the `Download JDK...` option from the menu
-2. Select Version: `17`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)`
+If Temurin 17 is not on the list, you should install it first:
+
+1. Select the **`Download JDK...`** option from the menu
+1. Pick **Version**: **`17`**, **Vendor**: **`Eclipse Temurin (AdoptOpenJDK HotSpot)`**
+
+
+
+#### 2. Set the Gradle JVM
+Make sure Gradle also uses Temurin 17:
-
+1. Go to **`Settings > Build, Execution, Deployment > Build Tools > Gradle`**
+1. Set **`Gradle JVM`** to **`temurin-17`**
-Now go back to your main window and
-1. Click the green Run Icon in the top right of the window.
+_Note: the exact path in settings may vary depending on your version of IntelliJ._
+
### “Duplicate content roots detected”
diff --git a/README.md b/README.md
index c71c919019..6c19b6923e 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,8 @@ For licensing information about the Processing website see the [processing-websi
Copyright (c) 2015-now The Processing Foundation
## Contributors
+
+
See [CONTRIBUTORS.md](./CONTRIBUTORS.md) for a list of all contributors to the project.
This project follows the [all-contributors specification](https://github.com/all-contributors/all-contributors) and the [Emoji Key](https://all-contributors.github.io/emoji-key/) ✨ for contribution types. Detailed instructions on how to add yourself or add contribution emojis to your name are [here](https://github.com/processing/processing4/issues/839). You can also post an issue or comment on a pull request with the text: `@all-contributors please add @YOUR-USERNAME for THINGS` (where `THINGS` is a comma-separated list of entries from the [list of possible contribution types](https://all-contributors.github.io/emoji-key/)) and our nice bot will add you to [CONTRIBUTORS.md](./CONTRIBUTORS.md) automatically!
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4f91e6d98c..0dbd48fdb9 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -186,7 +186,7 @@ tasks.register("packageCustomDmg"){
onlyIf { OperatingSystem.current().isMacOsX }
group = "compose desktop"
- dependsOn(distributable(), "installCreateDmg")
+ dependsOn("signApp", "installCreateDmg")
val packageName = distributable().packageName.get()
val dir = distributable().destinationDir.get()
@@ -359,12 +359,12 @@ tasks.register("zipDistributable"){
dependsOn("createDistributable", "setExecutablePermissions")
group = "compose desktop"
- val dir = distributable().destinationDir.get()
- val packageName = distributable().packageName.get()
+ val dir = provider { distributable().destinationDir.get() }
+ val packageName = provider { distributable().packageName.get() }
from(dir){ eachFile{ permissions{ unix("755") } } }
archiveBaseName.set(packageName)
- destinationDirectory.set(dir.file("../").asFile)
+ destinationDirectory.set(layout.dir(provider { dir.get().file("../").asFile }))
}
afterEvaluate{
@@ -390,6 +390,25 @@ afterEvaluate{
}
}
+val verifySignedMacApp = tasks.register("verifySignedMacApp") {
+ onlyIf { OperatingSystem.current().isMacOsX }
+ dependsOn("createDistributable")
+ group = "compose desktop"
+
+ commandLine(
+ "codesign",
+ "-vvv",
+ "--deep",
+ "--strict",
+ layout.buildDirectory.dir("compose/binaries/main/app/Processing.app").get().asFile.absolutePath
+ )
+}
+
+afterEvaluate {
+ tasks.named("notarizeDmg").configure {
+ dependsOn(verifySignedMacApp)
+ }
+}
// LEGACY TASKS
// Most of these are shims to be compatible with the old build system
@@ -571,9 +590,35 @@ tasks.register("signResources"){
}
file(composeResources("Info.plist")).delete()
}
+}
+
+/* for mac, perform one final signature of the whole app before submitting
+ * the app for notarization.
+ */
+tasks.register("signApp"){
+ onlyIf {
+ OperatingSystem.current().isMacOsX
+ &&
+ compose.desktop.application.nativeDistributions.macOS.signing.sign.get()
+ }
+
+ group = "compose desktop"
+ dependsOn("createDistributable", "setExecutablePermissions")
+ val packageName = distributable().packageName.get()
+ val dir = distributable().destinationDir.get()
+ val app = dir.file("$packageName.app").asFile
+ commandLine(
+ "codesign",
+ "--timestamp",
+ "--force",
+ "--deep",
+ "--options=runtime",
+ "--sign", "Developer ID Application",
+ app)
}
+
tasks.register("setExecutablePermissions") {
description = "Sets executable permissions on binaries in Processing.app resources"
group = "compose desktop"
diff --git a/contributors.png b/contributors.png
new file mode 100644
index 0000000000..2f252b0b17
Binary files /dev/null and b/contributors.png differ
diff --git a/core/src/processing/data/Table.java b/core/src/processing/data/Table.java
index ca04dd6ab7..401a4a86ee 100644
--- a/core/src/processing/data/Table.java
+++ b/core/src/processing/data/Table.java
@@ -224,22 +224,27 @@ public Table(ResultSet rs) {
int type = rsmd.getColumnType(col + 1);
switch (type) { // TODO these aren't tested. nor are they complete.
- case Types.INTEGER:
- case Types.TINYINT:
- case Types.SMALLINT:
- setColumnType(col, INT);
- break;
- case Types.BIGINT:
- setColumnType(col, LONG);
- break;
- case Types.FLOAT:
- setColumnType(col, FLOAT);
- break;
- case Types.DECIMAL:
- case Types.DOUBLE:
- case Types.REAL:
- setColumnType(col, DOUBLE);
- break;
+ case Types.VARCHAR:
+ case Types.CHAR:
+ case Types.BLOB:
+ setColumnType(col, STRING);
+ break;
+ case Types.INTEGER:
+ case Types.TINYINT:
+ case Types.SMALLINT:
+ setColumnType(col, INT);
+ break;
+ case Types.BIGINT:
+ setColumnType(col, LONG);
+ break;
+ case Types.FLOAT:
+ setColumnType(col, FLOAT);
+ break;
+ case Types.DECIMAL:
+ case Types.DOUBLE:
+ case Types.REAL:
+ setColumnType(col, DOUBLE);
+ break;
}
}
diff --git a/core/test/processing/core/PGraphicsTests.java b/core/test/processing/core/PGraphicsTests.java
new file mode 100644
index 0000000000..8d30b8fb71
--- /dev/null
+++ b/core/test/processing/core/PGraphicsTests.java
@@ -0,0 +1,19 @@
+package processing.core;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import processing.core.PGraphics;
+
+public class PGraphicsTests {
+
+ @Test
+ public void testCanvasSizeAfterSetSize() {
+ // Create a PGraphics object and set its size
+ PGraphics pg = new PGraphics();
+ pg.setSize(200, 150);
+
+ // Assert that both width and height are correctly initialized
+ assertEquals(200, pg.width);
+ assertEquals(150, pg.height);
+ }
+}
\ No newline at end of file
diff --git a/java/gradle/README.md b/java/gradle/README.md
index b827972769..d49d609764 100644
--- a/java/gradle/README.md
+++ b/java/gradle/README.md
@@ -18,7 +18,9 @@ more advanced workflows.
## What is Gradle
Gradle is a build tool commonly used in the Java ecosystem. It is responsible for tasks like compiling code, managing
-dependencies, and running applications. You do not need to learn Gradle to use Processing in the P
+dependencies, and running applications. You do not need to learn Gradle to use Processing in the PDE, but if you feel
+ready to take your sketches beyond the PDE and into development environments such as IntelliJ or Eclipse, this plugin
+helps bridge the gap between Processing and standard Java workflows.
## Usage
@@ -110,4 +112,4 @@ plugins {
`settings.gradle.kts` - create the file but leave blank
-Then run all sketches at once with `gradle sketch`
\ No newline at end of file
+Then run all sketches at once with `gradle sketch`
diff --git a/utils/contributors-png.js b/utils/contributors-png.js
new file mode 100644
index 0000000000..2686f1685f
--- /dev/null
+++ b/utils/contributors-png.js
@@ -0,0 +1,61 @@
+const { createCanvas, loadImage } = require('canvas');
+const fs = require('fs');
+
+const data = fs.readFileSync('.all-contributorsrc', 'utf-8');
+const parsed = JSON.parse(data);
+const contributors = parsed.contributors;
+
+const AVATAR_SIZE = 50;
+const GAP = 4;
+const COLS = 40;
+const ROWS = Math.ceil(contributors.length / COLS);
+
+const width = COLS * AVATAR_SIZE + (COLS - 1) * GAP;
+const height = ROWS * AVATAR_SIZE + (ROWS - 1) * GAP;
+
+const canvas = createCanvas(width, height);
+const ctx = canvas.getContext('2d');
+
+async function loadAvatar(url) {
+ try {
+ const res = await fetch(url);
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+
+ const buffer = Buffer.from(await res.arrayBuffer());
+ return await loadImage(buffer);
+ } catch (err) {
+ return null;
+ }
+}
+
+(async () => {
+ for (let i = 0; i < contributors.length; i++) {
+ const c = contributors[i];
+
+ const col = i % COLS;
+ const row = Math.floor(i / COLS);
+
+ const x = col * (AVATAR_SIZE + GAP);
+ const y = row * (AVATAR_SIZE + GAP);
+
+ const img = await loadAvatar(c.avatar_url);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.arc(
+ x + AVATAR_SIZE / 2,
+ y + AVATAR_SIZE / 2,
+ AVATAR_SIZE / 2,
+ 0,
+ Math.PI * 2
+ );
+ ctx.clip();
+
+ if (img) {
+ ctx.drawImage(img, x, y, AVATAR_SIZE, AVATAR_SIZE);
+ }
+ ctx.restore();
+ }
+
+ fs.writeFileSync('contributors.png', canvas.toBuffer('image/png'));
+})();