pappl-printer(3)
๐ pappl-printer โ pappl printer functions ๐
okay so bestie, welcome to pappl-printer(3), one of the pappl printer functions pages. this is part 1 of 5, so grab a snack ๐ and let's get into it, because this one is a whole API surface and i am obsessed.
โจ NAME โจ
pappl-printer โ pappl printer functions
๐ LIBRARY ๐
Printer Application Framework (libpappl, pkg-config --cflags --libs pappl)
like literally just link it with that pkg-config incantation and you're golden ๐
๐ฆ SYNOPSIS ๐ฆ
first, the include. don't forget it, i beg:
#include <pappl/pappl.h>
then the opaque type, the main character itself:
typedef struct _pappl_printer_s pappl_printer_t;
and now the full lineup, no skips, no shuffles, in order, periodt:
void
papplPrinterCancelAllJobs(pappl_printer_t *printer);
void
papplPrinterCloseDevice(pappl_printer_t *printer);
pappl_printer_t *
papplPrinterCreate(pappl_system_t *system, int printer_id, const char
*printer_name, const char *driver_name, const char *device_id, const
char *device_uri);
void
papplPrinterDelete(pappl_printer_t *printer);
pappl_job_t *
papplPrinterFindJob(pappl_printer_t *printer, int job_id);
pappl_contact_t *
papplPrinterGetContact(pappl_printer_t *printer, pappl_contact_t
*contact);
const char *
papplPrinterGetDeviceID(pappl_printer_t *printer);
const char *
papplPrinterGetDeviceURI(pappl_printer_t *printer);
char *
papplPrinterGetDNSSDName(pappl_printer_t *printer, char *buffer, size_t
bufsize);
ipp_t *
papplPrinterGetDriverAttributes(pappl_printer_t *printer);
pappl_driver_data_t *
papplPrinterGetDriverData(pappl_printer_t *printer, pappl_driver_data_t
*data);
const char *
papplPrinterGetDriverName(pappl_printer_t *printer);
char *
papplPrinterGetGeoLocation(pappl_printer_t *printer, char *buffer,
size_t bufsize);
int
papplPrinterGetID(pappl_printer_t *printer);
int
papplPrinterGetImpressionsCompleted(pappl_printer_t *printer);
char *
papplPrinterGetLocation(pappl_printer_t *printer, char *buffer, size_t
bufsize);
int
papplPrinterGetMaxActiveJobs(pappl_printer_t *printer);
int
papplPrinterGetMaxCompletedJobs(pappl_printer_t *printer);
const char *
papplPrinterGetName(pappl_printer_t *printer);
int
papplPrinterGetNextJobID(pappl_printer_t *printer);
int
papplPrinterGetNumberOfActiveJobs(pappl_printer_t *printer);
int
papplPrinterGetNumberOfCompletedJobs(pappl_printer_t *printer);
int
papplPrinterGetNumberOfJobs(pappl_printer_t *printer);
char *
papplPrinterGetOrganization(pappl_printer_t *printer, char *buffer,
size_t bufsize);
char *
papplPrinterGetOrganizationalUnit(pappl_printer_t *printer, char
*buffer, size_t bufsize);
char *
papplPrinterGetPrintGroup(pappl_printer_t *printer, char *buffer, size_t
bufsize);
pappl_preason_t
papplPrinterGetReasons(pappl_printer_t *printer);
ipp_pstate_t
papplPrinterGetState(pappl_printer_t *printer);
int
papplPrinterGetSupplies(pappl_printer_t *printer, int max_supplies,
pappl_supply_t *supplies);
pappl_system_t *
papplPrinterGetSystem(pappl_printer_t *printer);
void
papplPrinterIterateActiveJobs(pappl_printer_t *printer, pappl_job_cb_t
cb, void *data, int first_index, int limit);
void
papplPrinterIterateAllJobs(pappl_printer_t *printer, pappl_job_cb_t cb,
void *data, int first_index, int limit);
void
papplPrinterIterateCompletedJobs(pappl_printer_t *printer,
pappl_job_cb_t cb, void *data, int first_index, int limit);
pappl_device_t *
papplPrinterOpenDevice(pappl_printer_t *printer);
void
papplPrinterPause(pappl_printer_t *printer);
void
papplPrinterResume(pappl_printer_t *printer);
void
papplPrinterSetContact(pappl_printer_t *printer, pappl_contact_t
*contact);
void
papplPrinterSetDNSSDName(pappl_printer_t *printer, const char *value);
void
papplPrinterSetDriverData(pappl_printer_t *printer, pappl_driver_data_t
*data, ipp_t *attrs);
void
papplPrinterSetDriverDefaults(pappl_printer_t *printer,
pappl_driver_data_t *data);
void
papplPrinterSetGeoLocation(pappl_printer_t *printer, const char *value);
void
papplPrinterSetImpressionsCompleted(pappl_printer_t *printer, int add);
void
papplPrinterSetLocation(pappl_printer_t *printer, const char *value);
void
papplPrinterSetMaxActiveJobs(pappl_printer_t *printer, int
max_active_jobs);
void
papplPrinterSetMaxCompletedJobs(pappl_printer_t *printer, int
max_completed_jobs);
void
papplPrinterSetNextJobID(pappl_printer_t *printer, int next_job_id);
void
papplPrinterSetOrganization(pappl_printer_t *printer, const char
*value);
void
papplPrinterSetOrganizationalUnit(pappl_printer_t *printer, const char
*value);
void
papplPrinterSetPrintGroup(pappl_printer_t *printer, const char *value);
void
papplPrinterSetReadyMedia(pappl_printer_t *printer, int num_ready,
pappl_media_col_t *ready);
void
papplPrinterSetReasons(pappl_printer_t *printer, pappl_preason_t add,
pappl_preason_t remove);
void
papplPrinterSetSupplies(pappl_printer_t *printer, int num_supplies,
pappl_supply_t *supplies);
void
papplPrinterSetUSB(pappl_printer_t *printer, unsigned vendor_id,
unsigned product_id, pappl_uoptions_t options);
yes that's a lot of functions. no i will not be normal about it. ๐
๐ธ DESCRIPTION ๐ธ
okay so the PAPPL printer functions give you access to the printer object. Printers get created and deleted by the printer application itself, but the life cycle of the pappl_printer_t objects? that's managed automatically by the system object for the printer application. you don't have to babysit them, bestie, the framework does it for you ๐ซถ
The papplPrinterCreate function creates a new printer while the papplPrinterDelete function deletes a printer.
The papplPrinterPause function stops a printer while the papplPrinterResume function starts a printer.
The papplPrinterGet functions get the current values associated with a printer while the papplPrinterSet functions set the current values associated with a printer. it's giving very get-and-set, very yin-and-yang ๐
The papplPrinterCancelAddJobs, papplPrinterFindJob, papplPrinterGetNumberOfActiveJobs, papplPrinterGetNumberOfCompletedJobs, papplPrinterGetNumberOfJobs, papplPrinterIterateActiveJobs, papplPrinterIterateAllJobs, and papplPrinterIterateCompletedJobs functions provide access to the jobs queued on a printer.
The papplPrinterOpenDevice function provides access to the device associated with a printer when it is not processing a job. The device must be later closed using the papplPrinterCloseDevice function so that the printer can resume job processing.
๐จ lowkey important: open it, then close it with papplPrinterCloseDevice โ otherwise the printer can't get back to processing jobs. don't leave it hanging, that's not the vibe.
part 2 is coming, stay tuned bestie, we're just getting started โจ๐
โจ ENUMERATIONS โจ
okay bestie, this is the big vibe library of enum values that PAPPL uses to talk IPP. every group is a bundle of bit values, and each one maps to a string that shows up in the actual IPP attributes. let's get into it ๐
๐จ pappl_color_mode_e
these are the IPP "print-color-mode" bit values, aka how much color the printer is gonna serve.
PAPPL_COLOR_MODE_AUTOโ'auto'- Automatic color/monochrome print modePAPPL_COLOR_MODE_AUTO_MONOCHROMEโ'auto-monochrome'- Automatic monochrome/process monochrome print modePAPPL_COLOR_MODE_BI_LEVELโ'bi-level'- B&W (threshold) print modePAPPL_COLOR_MODE_COLORโ'color'- Full color print modePAPPL_COLOR_MODE_MONOCHROMEโ'monochrome'- Grayscale print mode using 1 colorPAPPL_COLOR_MODE_PROCESS_MONOCHROMEโ'process-monochrome'- Grayscale print mode using multiple colors
๐ pappl_content_e
IPP "print-content-optimize" bit values โ basically telling the printer "hey, here's what kind of stuff I'm sending you".
PAPPL_CONTENT_AUTOโ'auto': Automatically determine contentPAPPL_CONTENT_GRAPHICโ'graphic': Optimize for vector graphicsPAPPL_CONTENT_PHOTOโ'photo': Optimize for photos/continuous tone imagesPAPPL_CONTENT_TEXTโ'text': Optimize for textPAPPL_CONTENT_TEXT_AND_GRAPHICโ'text-and-graphic': Optimize for text and vector graphics
๐ฆ pappl_duplex_e
duplex printing support, i.e. can it print on both sides and how does it flip them.
PAPPL_DUPLEX_FLIPPEDโ Duplex with flipped back sidesPAPPL_DUPLEX_MANUAL_TUMBLEโ Duplex with back side rotated 180 degrees for short-edge duplexPAPPL_DUPLEX_NONEโ No duplex printing supportPAPPL_DUPLEX_NORMALโ Duplex with normal back sidesPAPPL_DUPLEX_ROTATEDโ Duplex with back side rotated 180 degrees for long-edge duplex
๐ pappl_finishings_e
IPP "finishings" bit values โ the little extras the printer can do to your sheets.
PAPPL_FINISHINGS_NONEโ'none'PAPPL_FINISHINGS_PUNCHโ'punch'PAPPL_FINISHINGS_STAPLEโ'staple'PAPPL_FINISHINGS_TRIMโ'trim'
๐ pappl_identify_actions_e
IPP "identify-actions" bit values โ how the printer gets your attention when you press the "which one are you" button. main character energy fr.
PAPPL_IDENTIFY_ACTIONS_DISPLAYโ'display': Display a messagePAPPL_IDENTIFY_ACTIONS_FLASHโ'flash': Flash the display or a lightPAPPL_IDENTIFY_ACTIONS_NONEโ No actionsPAPPL_IDENTIFY_ACTIONS_SOUNDโ'sound': Make a soundPAPPL_IDENTIFY_ACTIONS_SPEAKโ'speak': Speak a message
๐จ๏ธ pappl_kind_e
IPP "printer-kind" bit values โ the printer's whole personality, what kind of media it eats.
PAPPL_KIND_DISCโ'disc'PAPPL_KIND_DOCUMENTโ'document'PAPPL_KIND_ENVELOPEโ'envelope'PAPPL_KIND_LABELโ'label'PAPPL_KIND_LARGE_FORMATโ'large-format'PAPPL_KIND_PHOTOโ'photo'PAPPL_KIND_POSTCARDโ'postcard'PAPPL_KIND_RECEIPTโ'receipt'PAPPL_KIND_ROLLโ'roll'
๐ท๏ธ pappl_label_mode_e
IPP "label-mode-xxx" bit values โ for the label-printer girlies specifically.
PAPPL_LABEL_MODE_APPLICATORโ'applicator'PAPPL_LABEL_MODE_CUTTERโ'cutter'PAPPL_LABEL_MODE_CUTTER_DELAYEDโ'cutter-delayed'PAPPL_LABEL_MODE_KIOSKโ'kiosk'PAPPL_LABEL_MODE_PEEL_OFFโ'peel-off'PAPPL_LABEL_MODE_PEEL_OFF_PREPEELโ'peel-off-prepeel'PAPPL_LABEL_MODE_REWINDโ'rewind'PAPPL_LABEL_MODE_RFIDโ'rfid'PAPPL_LABEL_MODE_TEAR_OFFโ'tear-off'
๐ pappl_media_tracking_e
IPP "media-tracking" bit values โ how the printer knows where the media actually is.
PAPPL_MEDIA_TRACKING_CONTINUOUSโ'continuous'PAPPL_MEDIA_TRACKING_GAPโ'gap'PAPPL_MEDIA_TRACKING_MARKโ'mark'PAPPL_MEDIA_TRACKING_WEBโ'web'
๐ญ pappl_preason_e
IPP "printer-state-reasons" bit values โ the printer telling you everything that's wrong with it. it's giving dramatic, honestly.
PAPPL_PREASON_COVER_OPENโ'cover-open'PAPPL_PREASON_DEVICE_STATUSโ SupportedpapplDeviceGetStatusbitsPAPPL_PREASON_DOOR_OPENโ'door-open'PAPPL_PREASON_IDENTIFY_PRINTER_REQUESTEDโ'identify-printer-requested'PAPPL_PREASON_INPUT_TRAY_MISSINGโ'input-tray-missing'PAPPL_PREASON_MARKER_SUPPLY_EMPTYโ'marker-supply-empty'PAPPL_PREASON_MARKER_SUPPLY_LOWโ'marker-supply-low'PAPPL_PREASON_MARKER_WASTE_ALMOST_FULLโ'marker-waste-almost-full'PAPPL_PREASON_MARKER_WASTE_FULLโ'marker-waste-full'PAPPL_PREASON_MEDIA_EMPTYโ'media-empty'PAPPL_PREASON_MEDIA_JAMโ'media-jam'PAPPL_PREASON_MEDIA_LOWโ'media-low'PAPPL_PREASON_MEDIA_NEEDEDโ'media-needed'PAPPL_PREASON_NONEโ'none'PAPPL_PREASON_OFFLINEโ'offline'PAPPL_PREASON_OTHERโ'other'PAPPL_PREASON_SPOOL_AREA_FULLโ'spool-area-full'PAPPL_PREASON_TONER_EMPTYโ'toner-empty'PAPPL_PREASON_TONER_LOWโ'toner-low'
๐ pappl_raster_type_e
IPP "pwg-raster-document-type-supported" bit values โ all the pixel formats the printer can vibe with.
PAPPL_PWG_RASTER_TYPE_ADOBE_RGB_16โ 16-bit per component AdobeRGBPAPPL_PWG_RASTER_TYPE_ADOBE_RGB_8โ 8-bit per component AdobeRGBPAPPL_PWG_RASTER_TYPE_BLACK_1โ 1-bit (device) blackPAPPL_PWG_RASTER_TYPE_BLACK_16โ 16-bit (device) blackPAPPL_PWG_RASTER_TYPE_BLACK_8โ 8-bit (device) blackPAPPL_PWG_RASTER_TYPE_CMYK_16โ 16-bit per component (device) CMYKPAPPL_PWG_RASTER_TYPE_CMYK_8โ 8-bit per component (device) CMYKPAPPL_PWG_RASTER_TYPE_NONEโ Do not force a particular raster typePAPPL_PWG_RASTER_TYPE_RGB_16โ 16-bit per component (device) RGBPAPPL_PWG_RASTER_TYPE_RGB_8โ 8-bit per component (device) RGBPAPPL_PWG_RASTER_TYPE_SGRAY_16โ 16-bit grayscale with 2.2 gammaPAPPL_PWG_RASTER_TYPE_SGRAY_8โ 8-bit grayscale with 2.2 gammaPAPPL_PWG_RASTER_TYPE_SRGB_16โ 16-bit per component sRGBPAPPL_PWG_RASTER_TYPE_SRGB_8โ 8-bit per component sRGB
๐ง pappl_scaling_e
IPP "print-scaling" bit values โ how the image gets resized to fit the paper. it's giving "will it fit? we'll find out".
PAPPL_SCALING_AUTOโ'auto': Scale to fit (non-borderless) or fill (borderless) if larger, otherwise centerPAPPL_SCALING_AUTO_FITโ'auto-fit': Scale to fit if larger, otherwise centerPAPPL_SCALING_FILLโ'fill': Scale to fill the mediaPAPPL_SCALING_FITโ'fit': Scale to fit within marginsPAPPL_SCALING_NONEโ'none': No scaling (center/crop)
๐ pappl_sides_e
IPP "sides" bit values โ one side or two, and which edge flips.
PAPPL_SIDES_ONE_SIDEDโ'one-sided'PAPPL_SIDES_TWO_SIDED_LONG_EDGEโ'two-sided-long-edge'PAPPL_SIDES_TWO_SIDED_SHORT_EDGEโ'two-sided-short-edge'
๐ pappl_uoptions_e
USB gadget options โ for when the printer is cosplaying as a USB device.
PAPPL_UOPTIONS_ETHERNETโ Include USB ethernet gadgetPAPPL_UOPTIONS_NONEโ No options (just USB printer)PAPPL_UOPTIONS_SERIALโ Include USB serial gadgetPAPPL_UOPTIONS_STORAGEโ Include USB mass storage gadgetPAPPL_UOPTIONS_STORAGE_READONLYโ USB mass storage gadget is read-onlyPAPPL_UOPTIONS_STORAGE_REMOVABLEโ USB mass storage gadget is removable
๐ FUNCTIONS ๐
okay so now the actual functions, bestie. this is where you build the printer, boss it around, and read stuff back out of it. every signature is here verbatim, don't @ me.
๐ธ papplPrinterCancelAllJobs
Cancel all jobs on the printer.
void papplPrinterCancelAllJobs (
pappl_printer_t *printer
);
This function cancels all jobs on the printer. If any job is currently being printed, it will be stopped at a convenient time (usually the end of a page) so that the printer will be left in a known state.
not me hitting the panic button on every single job at once ๐ญ but fr it's polite about it โ the currently-printing one gets stopped at a convenient time (usually the end of a page) so the printer ends up in a known state instead of just yanked mid-page.
๐ช papplPrinterCloseDevice
Close the device associated with the printer.
void papplPrinterCloseDevice (
pappl_printer_t *printer
);
This function closes the device for a printer. The device must have been previously opened using the papplPrinterOpenDevice function.
heads up bestie: you can only close a device that was opened with papplPrinterOpenDevice first. don't try to close something that was never opened. ๐
๐ papplPrinterCreate
Create a new printer.
pappl_printer_t * papplPrinterCreate (
pappl_system_t *system,
int printer_id,
const char *printer_name,
const char *driver_name,
const char *device_id,
const char *device_uri
);
This function creates a new printer (service) on the specified system. The "type" argument specifies the type of service to create and must currently be the value PAPPL_SERVICE_TYPE_PRINT.
The "printer_id" argument specifies a positive integer identifier that is unique to the system. If you specify a value of 0 a new identifier will be assigned.
The "driver_name" argument specifies a named driver for the printer, from the list of drivers registered with the papplSystemSetPrinterDrivers function.
The "device_id" and "device_uri" arguments specify the IEEE-1284 device ID and device URI strings for the printer.
On error, this function sets the errno variable to one of the following values:
EEXIST: A printer with the specified name already exists.EINVAL: Bad values for the arguments were specified.EIO: The driver callback failed.ENOENT: No driver callback has been set.ENOMEM: Ran out of memory.
bestie this is the birth of a whole printer, the origin story, main character debut โจ. give it0forprinter_idand it'll pick a fresh unique one for you. slay.
๐๏ธ papplPrinterDelete
Delete a printer.
void papplPrinterDelete (
pappl_printer_t *printer
);
This function deletes a printer from a system, freeing all memory and canceling all jobs as needed.
it really said "and I took that personally" โ printer gone, memory freed, jobs canceled as needed. no loose ends. periodt.
๐ papplPrinterDisable
Stop accepting jobs on a printer.
void papplPrinterDisable (
pappl_printer_t *printer
);
This function stops accepting jobs on a printer.
closing the queue, the printer is on do-not-disturb mode rn ๐.
โ papplPrinterEnable
Start accepting jobs on a printer.
void papplPrinterEnable (
pappl_printer_t *printer
);
This function starts accepting jobs on a printer.
and we're SO back. the printer is open for business again ๐ .
๐ papplPrinterGetContact
Get the "printer-contact" value.
pappl_contact_t * papplPrinterGetContact (
pappl_printer_t *printer,
pappl_contact_t *contact
);
This function copies the current printer contact information to the buffer pointed to by the "contact" argument.
๐ papplPrinterGetDNSSDName
Get the current DNS-SD service name.
char * papplPrinterGetDNSSDName (
pappl_printer_t *printer,
char *buffer,
size_t bufsize
);
This function copies the current DNS-SD service name to the buffer pointed to by the "buffer" argument.
๐ท๏ธ papplPrinterGetDeviceID
Get the IEEE-1284 device ID of the printer.
const char * papplPrinterGetDeviceID (
pappl_printer_t *printer
);
This function returns the IEEE-1284 device ID of the printer.
๐ papplPrinterGetDeviceURI
Get the URI of the device associated with the printer.
const char * papplPrinterGetDeviceURI (
pappl_printer_t *printer
);
This function returns the device URI for the printer.
๐ papplPrinterGetDriverAttributes
Get a copy of the current driver attributes.
ipp_t * papplPrinterGetDriverAttributes (
pappl_printer_t *printer
);
This function returns a copy the current driver attributes. Use the ippDelete function to free the memory used for the attributes when you are done.
bestie it's a copy, so that memory is yours to clean up. call ippDelete when you're done or you'll be leaking like a broken water bottle ๐ฅค๐.
๐จ๏ธ papplPrinterGetDriverData
Get the current print driver data.
papplPrinterGetDriverData ๐พ
pappl_pr_driver_data_t * papplPrinterGetDriverData (
pappl_printer_t *printer,
pappl_pr_driver_data_t *data
);
bestie this one copies the current print driver data, the defaults, and the ready (loaded) media info right into the buffer you handed it โจ everything, in one go.
papplPrinterGetDriverName ๐ท๏ธ
const char * papplPrinterGetDriverName (
pappl_printer_t *printer
);
returns the driver name for the printer. that's it, that's the whole vibe ๐
papplPrinterGetGeoLocation ๐
char * papplPrinterGetGeoLocation (
pappl_printer_t *printer,
char *buffer,
size_t bufsize
);
copies the currently configured geographic location โ as a "geo:" URI โ into the buffer that the buffer argument points at ๐
papplPrinterGetID ๐ข
int papplPrinterGetID (
pappl_printer_t *printer
);
returns the printer's unique positive integer identifier. yes queen, it's an int ๐
papplPrinterGetImpressionsCompleted ๐จ๏ธ
int papplPrinterGetImpressionsCompleted (
pappl_printer_t *printer
);
returns how many impressions have been printed. and ngl, an impression is one side of an output page โ so don't come for me thinking it's a whole sheet, because one sheet can lowkey be two impressions ๐ซถ
papplPrinterGetLocation ๐
char * papplPrinterGetLocation (
pappl_printer_t *printer,
char *buffer,
size_t bufsize
);
copies the printer's human-readable location into the buffer pointed to by the buffer argument. cute little "where is this thing physically at" string, love that for us ๐
papplPrinterGetMaxActiveJobs ๐ฅ
int papplPrinterGetMaxActiveJobs (
pappl_printer_t *printer
);
returns the maximum number of active jobs the printer supports โ meaning jobs that are queued โ as configured by the papplPrinterSetMaxActiveJobs function โญ
papplPrinterGetMaxCompletedJobs ๐
int papplPrinterGetMaxCompletedJobs (
pappl_printer_t *printer
);
returns the max number of jobs that get retained for history by the printer, as configured by the papplPrinterSetMaxCompletedJobs function ๐ธ
papplPrinterGetMaxPreservedJobs ๐๏ธ
int papplPrinterGetMaxPreservedJobs (
pappl_printer_t *printer
);
returns the maximum number of jobs that are retained โ and this time including the document data โ in the job history, as configured by the papplPrinterSetMaxPreservedJobs function ๐ฅ
papplPrinterGetName ๐
const char * papplPrinterGetName (
pappl_printer_t *printer
);
returns the printer's human-readable name. the main character's name, if you will โจ
papplPrinterGetNextJobID โญ๏ธ
int papplPrinterGetNextJobID (
pappl_printer_t *printer
);
returns the positive integer identifier that's gonna be used for the next job that gets created. like a lil sneak peek of the future ๐ฎ
papplPrinterGetNumberOfActiveJobs ๐
int papplPrinterGetNumberOfActiveJobs (
pappl_printer_t *printer
);
returns the number of print jobs that are either printing or waiting to be printed. busy busy ๐
papplPrinterGetNumberOfCompletedJobs โ
int papplPrinterGetNumberOfCompletedJobs (
pappl_printer_t *printer
);
returns the number of print jobs that have been aborted, canceled, or completed. the finished-arc era ๐
papplPrinterGetNumberOfJobs ๐งฎ
int papplPrinterGetNumberOfJobs (
pappl_printer_t *printer
);
returns the number of print jobs that are printing, waiting to be printed, have been aborted, have been canceled, or have completed. literally every job, the whole roster ๐
papplPrinterGetOrganization ๐ข
char * papplPrinterGetOrganization (
pappl_printer_t *printer,
char *buffer,
size_t bufsize
);
copies the printer's organization name into the buffer pointed to by the buffer argument ๐ซถ
papplPrinterGetOrganizationalUnit ๐๏ธ
char * papplPrinterGetOrganizationalUnit (
pappl_printer_t *printer,
char *buffer,
size_t bufsize
);
copies the printer's organizational unit name into the buffer pointed to by the buffer argument. yes, the org unit is a whole separate thing from the org, don't @ me ๐ธ
papplPrinterGetPath ๐
char * papplPrinterGetPath (
pappl_printer_t *printer,
const char *subpath,
char *buffer,
size_t bufsize
);
generates and returns the URL path for the printer's web page. the subpath argument lets you spec an optional sub-path for a specific printer web page, if you're feeling specific โจ
papplPrinterGetPrintGroup ๐
char * papplPrinterGetPrintGroup (
pappl_printer_t *printer,
char *buffer,
size_t bufsize
);
copies the printer's authorization group name into the buffer pointed to by the buffer argument. and if there isn't one? there just isn't one, iykyk ๐
papplPrinterGetReasons ๐จ
pappl_preason_t papplPrinterGetReasons (
pappl_printer_t *printer
);
returns the current "printer-state-reasons" bitfield. it can get updated by the printer driver and/or by the papplPrinterSetReasons function โ so it's very much a living document fr fr ๐ฃ
papplPrinterGetState ๐
ipp_pstate_t papplPrinterGetState (
pappl_printer_t *printer
);
returns the current "printer-state" value as an enumeration. here's the whole lineup:
IPP_PSTATE_IDLEโ the printer is idle and has no jobs to process. resting era ๐IPP_PSTATE_PROCESSINGโ the printer is processing a job and/or producing output. working era ๐ฅIPP_PSTATE_STOPPEDโ the printer is stopped for maintenance. </li></ul>
that trailing </li></ul> is just vibing there, exactly like in the source. we don't question it, we just respect it ๐
papplPrinterGetSupplies ๐ง
int papplPrinterGetSupplies (
pappl_printer_t *printer,
int max_supplies,
pappl_supply_t *supplies
);
copies the current printer supply values into the array you specified. and here's the cute lil trick: the max_supplies and supplies arguments can be 0 and NULL if you just wanna query how many supplies are in play ๐
the return value is the actual number of supplies used by the printer, regardless of the size of the array. so it always tells you the truth, no cap ๐
papplPrinterGetSystem ๐ฅ๏ธ
pappl_system_t * papplPrinterGetSystem (
pappl_printer_t *printer
);
returns a pointer to the system object that contains the printer. it's giving "who's your parent" energy ๐ซถ
papplPrinterHoldNewJobs โ
bool papplPrinterHoldNewJobs (
pappl_printer_t *printer
);
this one holds any new jobs for printing, and it's typically used before you go do printer maintenance. existing jobs will finish printing, but new jobs get held until you call papplPrinterReleaseHeldNewJobs. so like, the queue is on pause but the current bop keeps playing ๐ง
papplPrinterIsAcceptingJobs ๐ฌ
bool papplPrinterIsAcceptingJobs (
pappl_printer_t *printer
);
returns a boolean value telling you whether the printer is accepting jobs. simple. iconic. ๐
papplPrinterIsDeleted ๐๏ธ
bool papplPrinterIsDeleted (
pappl_printer_t *printer
);
returns a boolean value telling you whether the printer is in the process of being deleted. yes bestie, mid-deletion is a whole state ๐ญ
papplPrinterIsHoldingNewJobs โธ๏ธ
bool papplPrinterIsHoldingNewJobs (
pappl_printer_t *printer
);
returns a boolean value telling you whether the printer is holding new jobs. the hold from papplPrinterHoldNewJobs? yeah, this is how you check if it's still on ๐ธ
papplPrinterIterateActiveJobs ๐
void papplPrinterIterateActiveJobs (
pappl_printer_t *printer,
pappl_job_cb_t cb,
void *data,
int job_index,
int limit
);
iterates over jobs that are either printing or waiting to be printed. your callback cb gets called once per job, and it gets handed the data pointer data ๐ซถ
the job_index argument sets the first job in the list to iterate, where 1 is the first job, etc. the limit argument caps the max number of jobs to iterate โ and you use 0 to iterate an unlimited number of jobs. go feral โจ
papplPrinterIterateAllJobs ๐
void papplPrinterIterateAllJobs (
pappl_printer_t *printer,
pappl_job_cb_t cb,
void *data,
int job_index,
int limit
);
iterates over all the jobs. your callback cb gets called once per job, with the data pointer data passed along ๐
the job_index argument sets the first job in the list to iterate, where 1 is the first job, etc. the limit argument caps the max number of jobs to iterate โ use 0 to iterate an unlimited number of jobs ๐ฅ
papplPrinterIterateCompletedJobs ๐
void papplPrinterIterateCompletedJobs (
pappl_printer_t *printer,
pappl_job_cb_t cb,
void *data,
int job_index,
int limit
);
iterates over jobs that are aborted, canceled, or completed. your callback cb gets called once per job, with the data pointer data ๐
the job_index argument sets the first job in the list to iterate, where 1 is the first job, etc. the limit argument caps the max number of jobs to iterate โ use 0 to iterate an unlimited number of jobs โญ
papplPrinterOpenDevice ๐
pappl_device_t * papplPrinterOpenDevice (
pappl_printer_t *printer
);
opens the printer's device. and heads up: NULL gets returned if the device is already in use โ for example while a job is being printed. one at a time, bestie, it's a whole thing ๐ค
the returned device must be closed using the papplPrinterCloseDevice function. don't just leave it open, that's rude ๐ซถ
papplPrinterOpenFile ๐
int papplPrinterOpenFile (
pappl_printer_t *printer,
char *fname,
size_t fnamesize,
const char *directory,
const char *resname,
const char *ext,
const char *mode
);
...and here's where it gets useful: this function creates, opens, or removes a file for a printer. ๐
The fname and fnamesize arguments are your little where-do-I-put-it pair โ they say where the buffer lives and how big it is. That buffer is gonna hold the printer filename, which mashes together the directory, the printer ID, the resource name, and the ext values. And the resource name? It gets "sanitized" first, bestie โ only alphanumeric characters survive. No funny business, no cap. ๐งผ
The mode argument has exactly three moods:
"r"โ read an existing printer file ๐"w"โ write a new printer file โ๏ธ"x"โ remove an existing printer file ๐๏ธ
Heads up: new files get created with restricted permissions for security purposes. That's not me being dramatic, that's just facts. ๐
Now the return values, because they differ depending on the mode and this is exactly the kind of thing that bites you:
- For the
"r"and"w"modes โ you get the file descriptor number on success, or-1on error. - For the
"x"mode โ you get0on success and-1on error.
And the errno variable is set appropriately on error. iykyk ๐
๐ซถ papplPrinterPause ๐ซถ
Pause (stop) a printer.
void papplPrinterPause (
pappl_printer_t *printer
);
This one pauses a printer. And the important bit, so listen up bestie: if the printer is currently processing (printing) a job, that job will be completed before the printer is stopped. So it's not a rage-quit, it's a "let me finish my sentence" kind of pause. ๐
๐ papplPrinterReleaseHeldNewJobs ๐
Release any previously held jobs for printing.
bool papplPrinterReleaseHeldNewJobs (
pappl_printer_t *printer,
const char *username
);
This function releases all jobs that were previously held because somebody (maybe you, no judgement ๐) called papplPrinterHoldNewJobs earlier. It's the un-holding. The letting-go. The release the prisoners moment. ๐ฆ
โญ papplPrinterResume โญ
Resume (start) a printer.
void papplPrinterResume (
pappl_printer_t *printer
);
This function resumes a printer and starts processing any pending jobs. Main character energy: it was paused, now it's back and it's booked and busy. ๐ฅ
๐ papplPrinterSetContact ๐
Set the "printer-contact" value.
void papplPrinterSetContact (
pappl_printer_t *printer,
pappl_contact_t *contact
);
This function sets the printer's contact information. Like, who do you @ when the toner runs out. ๐
๐ธ papplPrinterSetDNSSDName ๐ธ
Set the DNS-SD service name.
void papplPrinterSetDNSSDName (
pappl_printer_t *printer,
const char *value
);
This function sets the printer's DNS-SD service name. And here's the plot twist: if you pass NULL, the printer will stop advertising the printer. Ghosting, but make it mDNS. ๐ป
โจ papplPrinterSetDriverData โจ
Set the driver data.
bool papplPrinterSetDriverData (
pappl_printer_t *printer,
pappl_pr_driver_data_t *data,
ipp_t *attrs
);
This function validates and sets the driver data, including all defaults and ready (loaded) media. It's the whole package deal, bestie. ๐ฆ
Note: This function regenerates all of the driver-specific capability attributes like"media-col-database","sides-supported", and so forth. Use thepapplPrinterSetDriverDefaultsorpapplPrinterSetReadyMediafunctions to efficiently change the"xxx-default"or"xxx-ready"values, respectively. Translation: this one is the heavy lifter, use the other two when you just want a lil tweak. ๐
๐ papplPrinterSetDriverDefaults ๐
Set the default print option values.
bool papplPrinterSetDriverDefaults (
pappl_printer_t *printer,
pappl_pr_driver_data_t *data,
int num_vendor,
cups_option_t *vendor
);
This function validates and sets the printer's default print options.
Note: UnlikepapplPrinterSetPrintDriverData, this function only changes the"xxx_default"members of the driver data and is considered lightweight. So like, a snack, not a whole meal. ๐
๐ papplPrinterSetGeoLocation ๐
Set the geo-location value as a "geo:" URI.
void papplPrinterSetGeoLocation (
pappl_printer_t *printer,
const char *value
);
This function sets the printer's geographic location as a "geo:" URI. And if you pass NULL, the location gets cleared to the 'unknown' value. Mysterious. Elusive. Nobody knows where it is. ๐บ๏ธ
๐ papplPrinterSetImpressionsCompleted ๐
Add impressions (sides) to the total count of printed impressions.
void papplPrinterSetImpressionsCompleted (
pappl_printer_t *printer,
int add
);
This function adds to the printer's impressions counter. And for the record, because the word "impression" is doing a lot here: an impression is one side of an output page. So double-sided = two impressions. Maths, bestie. ๐งฎ
๐ฆ papplPrinterSetLocation ๐ฆ
Set the location string.
void papplPrinterSetLocation (
pappl_printer_t *printer,
const char *value
);
This function sets the printer's human-readable location string. If NULL, the location is cleared. This is the "second floor, by the sad plant" field. ๐ชด
๐ papplPrinterSetMaxActiveJobs ๐
Set the maximum number of active jobs for the printer.
void papplPrinterSetMaxActiveJobs (
pappl_printer_t *printer,
int max_active_jobs
);
This function sets the maximum number of jobs that can be spooled on the printer at one time. It's the velvet rope. ๐ง
Note: This limit does not apply to streaming raster formats such as PWG Raster since they are not spooled. They just walk right in, no line, no list. ๐
๐ papplPrinterSetMaxCompletedJobs ๐
Set the maximum number of completed jobs for the printer.
void papplPrinterSetMaxCompletedJobs (
pappl_printer_t *printer,
int max_completed_jobs
);
This function sets the maximum number of aborted, canceled, or completed jobs that are retained in the job history. It's the archive size. The receipts folder. ๐๏ธ
๐ธ papplPrinterSetMaxPreservedJobs ๐ธ
Set the maximum number of preserved jobs for the printer.
void papplPrinterSetMaxPreservedJobs (
pappl_printer_t *printer,
int max_preserved_jobs
);
This function sets the maximum number of aborted, canceled, or completed jobs that are preserved (with document data) in the job history. Yeah โ with the actual document data. That's the difference from the completed-jobs one. Big distinction, don't sleep on it. ๐ญ
โญ papplPrinterSetNextJobID โญ
Set the next "job-id" value.
void papplPrinterSetNextJobID (
pappl_printer_t *printer,
int next_job_id
);
This function sets the next unique positive integer identifier that will be used for a job. ๐๏ธ
Note: This function is normally only called once to restore the previous state of the printer. Not a thing you casually spam, bestie.
๐ papplPrinterSetOrganization ๐
Set the organization name.
void papplPrinterSetOrganization (
pappl_printer_t *printer,
const char *value
);
This function sets the printer's organization name. If NULL the value is cleared. ๐ข
โจ papplPrinterSetOrganizationalUnit โจ
Set the organizational unit name.
void papplPrinterSetOrganizationalUnit (
pappl_printer_t *printer,
const char *value
);
This function sets the printer's organizational unit name. If NULL the value is cleared. Yeah it's basically the same shape as the last one but for the unit โ the department, the squad, the little corner of the org chart. ๐ซถ
๐ฅ papplPrinterSetPrintGroup ๐ฅ
Set the print authorization group, if any.
void papplPrinterSetPrintGroup (
pappl_printer_t *printer,
const char *value
);
This function sets the printer's authorization group. If NULL, the group is cleared. The VIP list. ๐๏ธ
Note: The authorization group is only used if the system is created with a named authorization service. No service, no list, no bouncer. ๐
๐ papplPrinterSetReadyMedia ๐
Set the ready (loaded) media.
bool papplPrinterSetReadyMedia (
pappl_printer_t *printer,
int num_ready,
pappl_media_col_t *ready
);
This function validates and sets the printer's ready (loaded) media. Like, what's actually in the trays right now, not what could theoretically be. ๐โจ
๐ papplPrinterSetReasons ๐
Add or remove values from "printer-state-reasons".
void papplPrinterSetReasons (
pappl_printer_t *printer,
pappl_preason_t add,
pappl_preason_t remove
);
This function updates the printer state reasons bitfield by clearing any bit values in the remove argument and setting any bit values in the add argument. Two knobs, one call โ add stuff, remove stuff, all in one go. ๐๏ธ
๐ papplPrinterSetSupplies ๐
Set/update the supplies for a printer.
void papplPrinterSetSupplies (
pappl_printer_t *printer,
int num_supplies,
pappl_supply_t *supplies
);
This function updates the supply information for the printer. Toner, ink, staples, the whole consumables situation. ๐งด
๐ง papplPrinterSetUSB ๐ง
Set the USB vendor and product IDs for a printer.
void papplPrinterSetUSB (
pappl_printer_t *printer,
unsigned vendor_id,
unsigned product_id,
pappl_uoptions_t options,
const char *storagefile,
pappl_pr_usb_cb_t usb_cb,
void *usb_cbdata
);
This function sets the USB vendor and product IDs for a printer as well as specifying USB gadget options when the printer is registered with the USB device controller. Yes, that's a lot of arguments. Yes, they all matter. No, we don't skip them. ๐
The usb_cb argument specifies a processing callback that is called for every byte of data sent from the USB host. And that callback is the one responsible for:
- interpreting the data
- writing data to the device
- handling back-channel data
That's a lot of responsibility for one little callback, honestly. Give it a raise. ๐
Note: USB gadget functionality is currently only available when running on Linux with compatible hardware such as the Raspberry Pi Zero and 4B. So if you're on something else, this is giving not today. ๐ฅฒ
๐๏ธ STRUCTURES ๐๏ธ
okay bestie, this is where the actual shapes live. These are the structs you'll be poking at with a stick, so let's go one by one โจ
๐ pappl_icon_s โ Printer PNG icon structure
this is literally just "here's my little picture, here's how big it is, here's what it's called":
struct pappl_icon_s
{
const void *data;
size_t datalen;
char filename[256];
};
๐ฆ pappl_media_col_s โ Media details structure
the full tea on a sheet of paper: margins, offsets, how big it is, what it's called, where it came from, what type it is, and how it's being tracked ๐
struct pappl_media_col_s
{
int bottom_margin;
int left_margin;
int left_offset;
int right_margin;
int size_length;
char size_name[64];
int size_width;
char source[64];
int top_margin;
int top_offset;
pappl_media_tracking_t tracking;
char type[64];
};
๐ฅ pappl_pr_driver_data_s โ Printer driver data
ngl this one is the big one. it's giving main character energy. every single thing your driver knows about itself lives here โ bins, colors, darkness, callbacks, icons, media, resolutions, speeds, sides, vendor strings, the whole vibe ๐
struct pappl_pr_driver_data_s
{
const char *bin[PAPPL_MAX_BIN];
int bin_default;
bool borderless;
int bottom_top;
pappl_color_mode_t color_default;
pappl_color_mode_t color_supported;
pappl_content_t content_default;
int darkness_configured;
int darkness_default;
int darkness_supported;
pappl_pr_delete_cb_t delete_cb;
pappl_duplex_t duplex;
void *extension;
const char *features[PAPPL_MAX_VENDOR];
pappl_finishings_t finishings;
pappl_raster_type_t force_raster_type;
const char *format;
pappl_dither_t gdither;
bool has_supplies;
pappl_icon_t icons[3];
pappl_pr_identify_cb_t identify_cb;
pappl_identify_actions_t identify_default;
pappl_identify_actions_t identify_supported;
bool input_face_up;
pappl_kind_t kind;
int left_offset_supported[2];
int left_right;
char make_and_model[128];
const char *media[PAPPL_MAX_MEDIA];
pappl_media_col_t media_default;
pappl_media_col_t media_ready[PAPPL_MAX_SOURCE];
pappl_label_mode_t mode_configured;
pappl_label_mode_t mode_supported;
int num_bin;
int num_features;
int num_media;
int num_resolution;
int num_source;
int num_type;
int num_vendor;
ipp_orient_t orient_default;
bool output_face_up;
pappl_dither_t pdither;
int ppm;
int ppm_color;
pappl_pr_printfile_cb_t printfile_cb;
ipp_quality_t quality_default;
pappl_raster_type_t raster_types;
pappl_pr_rendjob_cb_t rendjob_cb;
pappl_pr_rendpage_cb_t rendpage_cb;
pappl_pr_rstartjob_cb_t rstartjob_cb;
pappl_pr_rstartpage_cb_t rstartpage_cb;
pappl_pr_rwriteline_cb_t rwriteline_cb;
pappl_scaling_t scaling_default;
pappl_sides_t sides_default;
pappl_sides_t sides_supported;
const char *source[PAPPL_MAX_SOURCE];
int speed_default;
int speed_supported[2];
pappl_pr_status_cb_t status_cb;
int tear_offset_configured;
int tear_offset_supported[2];
pappl_pr_testpage_cb_t testpage_cb;
int top_offset_supported[2];
pappl_media_tracking_t tracking_supported;
const char *type[PAPPL_MAX_TYPE];
const char *vendor[PAPPL_MAX_VENDOR];
int x_default;
int x_resolution[PAPPL_MAX_RESOLUTION];
int y_default;
int y_resolution[PAPPL_MAX_RESOLUTION];
};
๐ธ pappl_pr_options_s โ Combined print job options
and this one is the job's wishlist โ everything the user asked for, all mushed together into one struct so your driver can just read it and go ๐ซถ
struct pappl_pr_options_s
{
int copies;
int darkness_configured;
pappl_dither_t dither;
pappl_finishings_t finishings;
unsigned first_page;
cups_page_header_t header;
unsigned last_page;
pappl_media_col_t media;
unsigned num_pages;
int num_vendor;
ipp_orient_t orientation_requested;
char output_bin[64];
pappl_color_mode_t print_color_mode;
pappl_content_t print_content_optimize;
int print_darkness;
ipp_quality_t print_quality;
pappl_scaling_t print_scaling;
int print_speed;
int printer_resolution[2];
pappl_sides_t sides;
cups_option_t *vendor;
};
โจ TYPES โจ
these are the lil' typedefs, the nicknames, the "we're not typing all that out every time" squad ๐
๐ pappl_color_mode_t
Bitfield for IPP "print-color-mode" values
typedef unsigned pappl_color_mode_t;
๐ pappl_content_t
Bitfield for IPP "print-content-optimize" values
typedef unsigned pappl_content_t;
๐ง pappl_default_cb_t
papplIterateDefaults callback
typedef void (*pappl_default_cb_t)(ipp_attribute_t *attr, void *data);
๐ง pappl_duplex_t
Duplex printing support
typedef enum pappl_duplex_e pappl_duplex_t;
๐ pappl_finishings_t
Bitfield for IPP "finishings" values
typedef unsigned pappl_finishings_t;
๐ pappl_icon_t
Printer PNG icon structure
typedef struct pappl_icon_s pappl_icon_t;
๐ pappl_identify_actions_t
Bitfield for IPP "identify-actions" values
typedef unsigned pappl_identify_actions_t;
๐ง pappl_job_cb_t
papplIterateXxxJobs callback function
typedef void (*pappl_job_cb_t)(pappl_job_t *job, void *data);
๐ pappl_kind_t
Bitfield for IPP "printer-kind" values
typedef unsigned pappl_kind_t;
๐ pappl_label_mode_t
Bitfield for IPP "label-mode-xxx" values
typedef unsigned short pappl_label_mode_t;
๐ฆ pappl_media_col_t
Media details structure
typedef struct pappl_media_col_s pappl_media_col_t;
๐ pappl_media_tracking_t
Bitfield for IPP "media-tracking" values
typedef unsigned short pappl_media_tracking_t;
๐ง pappl_pr_delete_cb_t
Printer deletion callback
typedef void (*pappl_pr_delete_cb_t)(pappl_printer_t *printer, pappl_pr_driver_data_t *data);
๐ง pappl_pr_identify_cb_t
Identify-Printer callback
typedef void (*pappl_pr_identify_cb_t)(pappl_printer_t *printer, pappl_identify_actions_t actions, const char *message);
๐ง pappl_pr_printfile_cb_t
Print a "raw" job callback
typedef bool (*pappl_pr_printfile_cb_t)(pappl_job_t *job, pappl_pr_options_t *options, pappl_device_t *device);
๐ง pappl_pr_rendjob_cb_t
End a raster job callback
typedef bool (*pappl_pr_rendjob_cb_t)(pappl_job_t *job, pappl_pr_options_t *options, pappl_device_t *device);
๐ง pappl_pr_rendpage_cb_t
End a raster page callback
typedef bool (*pappl_pr_rendpage_cb_t)(pappl_job_t *job, pappl_pr_options_t *options, pappl_device_t *device, unsigned page);
๐ง pappl_pr_rstartjob_cb_t
Start a raster job callback
typedef bool (*pappl_pr_rstartjob_cb_t)(pappl_job_t *job, pappl_pr_options_t *options, pappl_device_t *device);
๐ง pappl_pr_rstartpage_cb_t
Start a raster page callback
typedef bool (*pappl_pr_rstartpage_cb_t)(pappl_job_t *job, pappl_pr_options_t *options, pappl_device_t *device, unsigned page);
๐ง pappl_pr_rwriteline_cb_t
Write a line of raster graphics callback
typedef bool (*pappl_pr_rwriteline_cb_t)(pappl_job_t *job, pappl_pr_options_t *options, pappl_device_t *device, unsigned y, const unsigned char *line);
๐ง pappl_pr_status_cb_t
Update printer status callback
typedef bool (*pappl_pr_status_cb_t)(pappl_printer_t *printer);
๐ง pappl_pr_testpage_cb_t
Print a test page callback
typedef const char * (*pappl_pr_testpage_cb_t)(pappl_printer_t *printer, char *buffer, size_t bufsize);
๐ง pappl_pr_usb_cb_t
Raw USB IO callback
typedef ssize_t (*pappl_pr_usb_cb_t)(pappl_printer_t *printer, pappl_device_t *device, void *buffer, size_t bufsize, size_t bytes, void *data);
๐ pappl_raster_type_t
Bitfield for IPP "pwg-raster-document-type-supported" values
typedef unsigned pappl_raster_type_t;
๐ pappl_scaling_t
Bitfield for IPP "print-scaling" values
typedef unsigned pappl_scaling_t;
๐ pappl_sides_t
Bitfield for IPP "sides" values
typedef unsigned pappl_sides_t;
๐ pappl_uoptions_t
USB gadget options bitfield
typedef unsigned pappl_uoptions_t;
๐ SEE ALSO ๐
go read your siblings, bestie, they're all iconic:
pappl(1)pappl-client(3)pappl-device(3)pappl-job(3)pappl-log(3)pappl-mainline(3)pappl-makeresheader(1)pappl-printer(3)pappl-resource(3)pappl-system(3)- https://www.msweet.org/pappl
๐ COPYRIGHT ๐
Copyright ยฉ 2019-2022 by Michael RUST? no โ Michael R Sweet. ๐
PAPPL is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software (like older versions of CUPS), so it can be used freely in any project you'd like. See the files "LICENSE" and "NOTICE" in the source distribution for more information.
fr fr, if you're shipping this in your project, go peek atLICENSEandNOTICE. it's giving "do your homework" but like, politely ๐ซถ
aaaand that's a wrap on the whole page, bestie!! ๐ this was pappl printer functions for pappl-printer(3), dated 2026-08-11 โ go forth and print things, you absolute legend ๐
โจ๐
๐ฆ where this page comes from
- arch rolling: pappl 1.4.12-1 ยท Apache-2.0 WITH LLVM-exception
- fedora 43: pappl-devel 1.4.12-1.fc43 ยท Apache-2.0 WITH LLVM-exception
- fedora 43: pappl-devel 1.4.12-1.fc43 ยท Apache-2.0 WITH LLVM-exception
- fedora 44: pappl-devel 1.4.12-1.fc44 ยท Apache-2.0 WITH LLVM-exception
- fedora 44: pappl-devel 1.4.12-1.fc44 ยท Apache-2.0 WITH LLVM-exception
- nixpkgs unstable: pappl 1.4.12
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms