You need to tell Springboot to fetch data in display mode or use %EXTERNAL function on column value. That's Java side.

Alternatively, on InterSystems side you can create a calculated property and access it in Java (replace !!! with full class name):

Property PetNameDisplay As %String  [ SqlComputeCode = {##class(!!!).PetNameLogicalToDisplay(##class(!!!).PetNameGetStored({%%ID}))}, SqlComputed, SqlComputeOnChange = (%%INSERT, %%UPDATE) ];

Remove SqlComputeOnChange  and add Calculated if you want it always computed instead of trigger-computed and stored.

I agree with general approach offered by @Julius Kavay, just wanted to add some notes:

1. Use $zf(-100) as a more secure alternative to $zf(-1) if it's available.

2. I'd go straight for imagemagick as it's crossplatform.

3. If speed is an issue you can consider using high-level MagickWand API (here's resize example) or low-level MagickCore API (here's resize functions) via Callout functionality. CoreAPI would be faster as there's in-memory image initializers so you can skip input/output file creation/consumption and work with inmemory streams.

This code will output arbitrary query to CSV.

/// w $System.Status.GetErrorText(##class(!!!).ToCSV())
ClassMethod ToCSV(file = {##class(%File).NormalizeDirectory(##class(%SYS.System).TempDirectory())_ "out"}, query As %String = "SELECT 1,2,'a'", args...) As %Status
{
    #dim sc As %Status = $$$OK
    // Cant't do $zcvt($e(file,*-4,*), "l") as it can bring unexpected effect on case-sensitive fs
    // Possible solution is to make file byref but it should be done in application code
    set:$e(file,*-4,*)=".csv" file = $e(file, 1, *-4)

    set dir = ##class(%File).GetDirectory(file)
    set exists = ##class(%File).DirectoryExists(dir)
    if (exists=$$$NO) {
        set success = ##class(%File).CreateDirectoryChain(dir, .code)
        set:success=$$$NO sc = $$$ERROR($$$GeneralError, "Unable to create directory: '" _ dir _ "', reason: " _ code)
    }
    quit:$$$ISERR(sc) sc

    #dim rs As %SQL.StatementResult
    set rs = ##class(%SQL.Statement).%ExecDirect(,query, args...)
    if rs.%SQLCODE=0 {
       do rs.%DisplayFormatted("CSV", file)
    } else {
        set sc = $$$ERROR($$$SQLError, rs.%SQLCODE, rs.%Message)
    }
    quit sc
}

I completely agree, and to get to

 standard installing mechanism 

for USERS, we need to zpm-enable as many existing projects as possible. To enable these projects we need to simplify the zpm-enabling, leveraging existing code if possible (or not preventing developers from leveraging the existing code). I think allowing developers to use already existing installers (whatever form they may take) would help with this goal.

I completely support inclusion of projections.

ObjectScript Language allows execution of arbitrary code at compile time through three different mechanisms:

  • Projections
  • Code generators
  • Macros

All these instruments are entirely unlimited in their scope, so I don't see why we need to prohibit one way of executing code at compilation.

Furthermore ZPM itself uses Projections to install itself so closing this avenue to other projects seems strange.