├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── binding.gyp ├── examples └── docker │ ├── .dockerignore │ ├── Dockerfile │ ├── index.js │ └── package.json ├── gs4js-env-dll.js ├── gs4js-env-home.js ├── gs4js-env-lib.js ├── index.js ├── lib ├── ghostscript4js.js └── index.js ├── macOS-lib-path-finder.js ├── node-love-ghostscript.png ├── package.json ├── src ├── ghostscript4js.cc ├── ghostscript4js.h └── iapi.h └── test ├── ghostscript4js.js ├── invalid.pdf ├── jasmine.json ├── node-love-ghostscript.pdf └── node-love-ghostscript.ps /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | npm-debug.log* 3 | 4 | # Compiled binary addons (http://nodejs.org/api/addons.html) 5 | build 6 | 7 | # Dependency directories 8 | node_modules 9 | 10 | # Metadata for IntelliJ IDEA IDEs 11 | .idea 12 | 13 | # Metadata for VSCode 14 | .vscode 15 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 3.2.3 / 2024-06-24 4 | 5 | * Fixed error on `package.json`. 6 | 7 | ## 3.2.2 / 2024-06-24 8 | 9 | * Fixed build error on macOS [#69](https://github.com/NickNaso/ghostscript4js/pull/69). 10 | 11 | ## 3.2.1 / 2020-02-24 12 | 13 | * Fixed typo on error message. 14 | 15 | ## 3.2.0 / 2020-02-24 16 | 17 | * Segmentation fault on multiple runs - Fix issue [#47](https://github.com/NickNaso/ghostscript4js/issues/47) 18 | * Execution stop with: double free or corruption - Fix issue [#49](https://github.com/NickNaso/ghostscript4js/issues/49) 19 | * Error when calling gs.executeSync - Fix issue [#50](https://github.com/NickNaso/ghostscript4js/issues/50) 20 | 21 | ## 3.1.1 / 2019-07-23 22 | 23 | * Improvements on documentation 24 | 25 | ## 3.1.0 / 2019-03-18 26 | 27 | * Fixed and improved the error handling. For more explanations see the PR [#41](https://github.com/NickNaso/ghostscript4js/pull/41) 28 | - Add unit test to intercept the error 29 | - Change GhostscriptManager to throw string instead of char* 30 | - Change SetError call to set exception string 31 | - Fix test to not hardcode ghostscript version to 2017 32 | 33 | ## 3.0.0 / 2018-07-05 34 | 35 | * Complete the port to N-API using node-addon-api 36 | * Undefinedfilename error on Windows if file path contains spaces - Fix issue [#33](https://github.com/NickNaso/ghostscript4js/issues/33) 37 | * Added code of conduct 38 | * Small updates on documentation - executeSync and execute function allow to pass array of strings as arguments. 39 | * Verified and updated the compatibility against the ghostscript version 9.23 40 | 41 | ## 2.0.11-n-api / 2018-03-22 42 | 43 | * Empty output with when using pdfwrite - Fix issue [#30](https://github.com/NickNaso/ghostscript4js/issues/30) 44 | * N-API porting of ghostscript4js - Fix issue [#29](https://github.com/NickNaso/ghostscript4js/issues/29) 45 | * Ghostscript 9.22 - Fix issue [#27](https://github.com/NickNaso/ghostscript4js/issues/27) 46 | 47 | ## 2.0.7 / 2017-02-09 48 | 49 | * Issue with the new update ghostscript4js@2.0.5 - Fix issue [#24](https://github.com/NickNaso/ghostscript4js/issues/24) 50 | 51 | ## 2.0.5 / 2017-01-09 52 | 53 | * GS4JS_LIB variable isn't used - Fix issue [#23](https://github.com/NickNaso/ghostscript4js/issues/23) 54 | 55 | ## 2.0.3 / 2017-30-06 56 | 57 | * Specify --c++11 and --libc++ cplusplus flags in node-gyp settings - PR [#22](https://github.com/NickNaso/ghostscript4js/pull/22) 58 | 59 | * Removed V8 API in the initialization code for the add-ons 60 | 61 | ## 2.0.1 / 2017-18-04 62 | 63 | * Warning on Microsoft compiler - Fix issue [#18](https://github.com/NickNaso/ghostscript4js/issues/18) 64 | 65 | * Removed unused file **g4js-env-home.js** 66 | 67 | ## 2.0.0 / 2017-18-04 68 | 69 | * **`ghostscript4js`** support for Ghostscript **9.21**. For more info see the [changelog](https://ghostscript.com/doc/9.21/News.htm). 70 | 71 | * Fix typo and other little errors in documentation. 72 | 73 | * Problem calling execute method multiple time consecutively - Fix issue [#15](https://github.com/NickNaso/ghostscript4js/issues/15). 74 | 75 | ## 1.0.19 / 2017-06-04 76 | 77 | * Invalid file path problem - Fix issue [#16](https://github.com/NickNaso/ghostscript4js/issues/16). 78 | 79 | ## 1.0.11 / 2017-11-03 80 | 81 | * Installation problem - Fix issue [#13](https://github.com/NickNaso/ghostscript4js/issues/14). 82 | 83 | ## 1.0.7 / 2017-03-03 84 | 85 | * Added compatibility with Ghostscript version. 86 | 87 | * Fix issue [#13](https://github.com/NickNaso/ghostscript4js/issues/13). 88 | 89 | ## 1.0.5 / 2017-02-22 90 | 91 | * Fix in documentation of **`ghostscript4js`**. 92 | 93 | ## 1.0.3 / 2017-02-20 94 | 95 | * Fix in documentation of **`ghostscript4js`**. 96 | 97 | ## 1.0.0 / 2017-02-20 98 | 99 | * Initial version of **`ghostscript4js`** binds the Ghostscript C API to bring Ghostscript power to the Node.JS world. 100 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at nicoladelgobbo@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Ghostscript4JS 6 | ## This module binds the Ghostscript C API to bring its power to the Node.JS world 7 | 8 | * [Introduction](#introduction) 9 | * [Motivations](#motivations) 10 | * [Prerequisites](#prerequisites) 11 | * [Installation](#install) 12 | * [Installation options](#installoptions) 13 | * [Usage](#usage) 14 | * [Docker](#docker) 15 | * [Code of conduct](CODE_OF_CONDUCT.md) 16 | * [Team](#team) 17 | * [Acknowledgements](#acknowledgements) 18 | * [License](#license) 19 | 20 | 21 | 22 | 23 | ## Introduction 24 | 25 | **Ghostscript** is a suite of software based on an interpreter for Adobe Systems' PostScript and Portable Document Format (PDF) 26 | page description languages. Its main purposes are the rasterization or rendering of such page description language files, 27 | for the display or printing of document pages, and the conversion between PostScript and PDF files. 28 | 29 | Ghostscript can be used as a raster image processor (RIP) for raster computer printers—for instance, as an input filter 30 | of line printer daemon—or as the RIP engine behind PostScript and PDF viewers. 31 | 32 | Ghostscript can also be used as a file format converter, such as PostScript to PDF converter. The **ps2pdf** conversion program, 33 | which comes with the ghostscript distribution, is described by its documentation as a "work-alike for nearly all the functionality 34 | (but not the user interface) of Adobe's Acrobat Distiller product".[3] This converter is basically a thin wrapper around 35 | ghostscript's pdfwrite output device, which supports PDF/A-1 and PDF/A-2 as well as PDF/X-3 output.[3] 36 | 37 | Ghostscript can also serve as the back-end for **PDF** to **raster image** (png, tiff, jpeg, etc.) converter; this is often 38 | combined with a PostScript printer driver in "virtual printer" PDF creators. 39 | 40 | As it takes the form of a language interpreter, Ghostscript can also be used as a general purpose programming environment. 41 | 42 | Ghostscript has been ported to many operating systems, including Unix-like systems, classic **Mac OS**, **OpenVMS**, **Microsoft Windows**, 43 | **Plan 9**, **MS-DOS**, **FreeDOS**, **OS/2**, **Atari TOS and AmigaOS**. 44 | 45 | ### More resource and info about Ghostscript 46 | 47 | * [Introduction to Ghostscript](https://www.gnu.org/software/ghostscript/intro.html) 48 | 49 | * [Ghostscript on Wikipedia](https://en.wikipedia.org/wiki/Ghostscript) 50 | 51 | * [Ghostscript documentation](https://www.ghostscript.com/Documentation.html) 52 | 53 | 54 | 55 | ## Motivations 56 | 57 | At the time i created this module i was not able to find any module on npm that execute Ghostscript command through its C API, 58 | otherwise there were some module that call Ghostscript through the execution of the corresponding shell command. This is a 59 | good way to start using some library from node, but there are the following drawbacks: 60 | 61 | * **Performance** - The call to the shell command take more time and more resources than calling a library C or C++ API directly from Node.js environment. 62 | 63 | * **Errror handler** - Sometimes you cannot intercept and handle errors in a good and a proper way. 64 | 65 | To fit all needs Ghostscript4JS has sync and async methods so it could be used in a web application where it's very important 66 | to not block the event loop, so all requests will be served without any delay originated by our application. 67 | 68 | [Understanding Node.js event loop](https://nodesource.com/blog/understanding-the-nodejs-event-loop/) 69 | 70 | 71 | 72 | ## Prerequisites 73 | 74 | Before installing Ghostscript4JS you need to assure you have the following prerequisites: 75 | 76 | * **Node.JS** see: [Installing Node.js via package manager](https://nodejs.org/en/download/package-manager/) 77 | 78 | * **Node.js native addon build tool** see: [node-gyp](https://github.com/nodejs/node-gyp) 79 | 80 | * **Ghostscript** for your Operating System. 81 | 82 | ## At moment Ghostscript4JS is fully compatible with Ghostscript from version 9.19 to 9.50 83 | 84 | ## Linux 85 | 86 | ### Debian systems 87 | 88 | Install Ghostscript 89 | 90 | ```bash 91 | apt-get install ghostscript libgs-dev 92 | ``` 93 | 94 | At this point you need to set the enviroment variable **GS4JS_HOME** to ```/usr/lib/x86_64-linux-gnu``` 95 | 96 | ### Red Hat | Fedora 97 | 98 | ```bash 99 | yum install ghostscript ghostscript-devel 100 | ``` 101 | 102 | At this point you need to set the enviroment variable **GS4JS_HOME** to ```/usr/lib64``` or ```/usr/lib``` based on you architecture 103 | 104 | ### Arch Linux 105 | ``` 106 | pacman -S ghostscript 107 | ``` 108 | At this point you need to set the enviroment variable **GS4JS_HOME** to ```/usr/lib``` 109 | 110 | ### Alpine 111 | ``` 112 | apk add ghostscript 113 | ``` 114 | At this point you need to set the enviroment variable **GS4JS_HOME** to ```/usr/lib``` 115 | 116 | In general, based on your Linux OS and architecture, you have to set the environment variable **GS4JS_HOME** to point on folder containing ```libgs.so``` library. 117 | 118 | ## Windows 119 | 120 | * Download last Ghostscript version for your platform [x86](https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs920/gs920w32.exe) or [x64](https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs920/gs920w64.exe) 121 | 122 | * Install Ghostscript on your system, for example in ```C:\gs``` 123 | 124 | * Add the environment variable **GS4JS_HOME** to point to a folder containing Ghostscript's DLL and Library files (Es. gsdll64.dll and gsdll64.lib). Typically, they are located in **bin** folder of you ghostscript installation, for example ```C:\gs\bin``` 125 | 126 | ## macOS 127 | 128 | * Install Homebrew following the official guide [here](https://brew.sh/index_it.html) 129 | 130 | * Open terminal and install Ghostscript 131 | 132 | ```bash 133 | brew install ghostscript 134 | ``` 135 | 136 | * Set the environment variable **GS4JS_HOME** to ```/usr/local/lib``` 137 | 138 | ## Official installation guide to install Ghostscript 139 | 140 | * [Installation from official documentation](https://ghostscript.com/doc/current/Install.htm) 141 | 142 | * [Download Ghostscript](https://ghostscript.com/download/gsdnld.html) 143 | 144 | 145 | 146 | ## Installation 147 | 148 | If you want to use ghostscript4js you have to install it. There are two methods for that: 149 | 150 | In dependencies of your ```package.json``` add the following item: 151 | 152 | ```json 153 | "ghostscript4js": "version" 154 | ``` 155 | 156 | then digit 157 | 158 | ```console 159 | npm install 160 | ``` 161 | 162 | **Example**: 163 | 164 | ```json 165 | "ghostscript4js": "*" for the latest version 166 | "ghostscript4js": "1.0.0" for the version 1.0.0 167 | ``` 168 | 169 | **OR** 170 | 171 | launch this command: 172 | 173 | ```console 174 | npm install ghostscript4js --save 175 | ``` 176 | 177 | 178 | 179 | ## Installation options 180 | 181 | The module ghostscript4js allows you to use some installation options that you can use when in your operating system something is different against standard installation. 182 | 183 | **--GS4JS_HOME** Set the GS4JS_HOME variable that represents the path in your system where is located the ghostscript library 184 | 185 | Es. ```npm install ghostscript4js --GS4JS_HOME="C:/gs/bin"``` 186 | 187 | **--GS4JS_LIB** Set the GS4JS_LIB variable that represents the file name for the ghostscript library installed in your system 188 | 189 | Es. ```npm install ghostscript4js --GS4JS_LIB="libgs.so"``` 190 | 191 | ### Only for Windows 192 | 193 | **--GS4JS_DLL** Set the GS4JS_DLL variable that represents the file name for the ghostscript DLL installed in your windows system 194 | 195 | Es. ```npm install ghostscript4js --GS4JS_DLL="gsdll64.dll"``` 196 | 197 | 198 | 199 | ## Usage 200 | 201 | ```js 202 | 'use strict' 203 | 204 | const gs = require('ghostscript4js') 205 | 206 | try { 207 | // Take decision based on Ghostscript version 208 | const version = gs.version() 209 | console.log(version) 210 | gs.executeSync('-sDEVICE=pngalpha -o my.png -sDEVICE=pngalpha -r144 my.pdf') 211 | } catch (err) { 212 | // Handle error 213 | throw err 214 | } 215 | ``` 216 | 217 | ## API 218 | 219 | ### version 220 | 221 | **version()** method returns an object that contains information about version of Ghostscript library 222 | installed on the system. It is important in those circumstances where you have to take 223 | decision based on different version. 224 | The returned data are similar to the example repoted below: 225 | 226 | ```js 227 | { 228 | product: "GPL Ghostscript", 229 | copyright: "Copyright (C) 2016 Artifex Software, Inc. All rights reserved.", 230 | revision: 919, 231 | revisiondate: 20160323 232 | } 233 | ``` 234 | 235 | This is a synchronous method and returns the version info or throws an Error to indicate that 236 | something went wrong during its execution. 237 | 238 | #### Example - version 239 | 240 | ```js 241 | 'use strict' 242 | 243 | const gs = require('ghostscript4js') 244 | 245 | try { 246 | const version = gs.version() 247 | console.log(version) 248 | // Take decision based on Ghostscript version 249 | if (version.revision > 916) { 250 | // ... some stuff 251 | } else { 252 | // ... other stuff 253 | } 254 | } catch (err) { 255 | // Handle error 256 | throw err 257 | } 258 | ``` 259 | 260 | ### executeSync 261 | 262 | **executeSync(cmd)** method takes the Ghostscript command parameters in input as a string or array of strings and executes in a synchronous way. 263 | If something wrong happens in calling this method an Error with description and code error will be thrown. 264 | 265 | #### Example - executeSync 266 | 267 | ```js 268 | 'use strict' 269 | 270 | const gs = require('ghostscript4js') 271 | 272 | try { 273 | gs.executeSync('-sDEVICE=pngalpha -o my.png -sDEVICE=pngalpha -r144 my.pdf') 274 | } catch (err) { 275 | // Handle error 276 | throw err 277 | } 278 | ``` 279 | 280 | ### execute 281 | 282 | **execute(cmd, callback)** method takes in input the Ghostscript command parameters as a string or array of strings and an optional callback. The execution will be asynchronous so this ensure better performance especially in a web application enviroment, because it'll not block the Node.Js event loop. 283 | This method has an optional callback function as input, in that case, a possible error will be handled by this function. If noone function will be provided the method returns a Promise that will be resolved or rejected as reported in the following example. 284 | 285 | #### Example - execute 286 | 287 | ```js 288 | 'use strict' 289 | 290 | const gs = require('ghostscript4js') 291 | 292 | let cmd = '-sDEVICE=pngalpha -o my.png -sDEVICE=pngalpha -r144 my.pdf' 293 | gs.execute(cmd, function (err) { 294 | if (err) { 295 | console.log("Ooops... something wrong happened") 296 | } 297 | }) 298 | 299 | ``` 300 | 301 | ```js 302 | 'use strict' 303 | 304 | const gs = require('ghostscript4js') 305 | 306 | let cmd = '-sDEVICE=pngalpha -o my.png -sDEVICE=pngalpha -r144 my.pdf' 307 | gs.execute(cmd) 308 | .then(() => { 309 | console.log("All is ok") 310 | }) 311 | .catch((err) => { 312 | console.log("Ooops... something wrong happened") 313 | }) 314 | 315 | ``` 316 | 317 | ### Error 318 | 319 | The error raised from **ghostscript4js** in all of its method is an instance of Error object that cointains a message that 320 | describes what happened and at the same time cointains the Ghostscript error code so you can inspect what happened in a better 321 | way. At this link [Ghostscript error codes](https://ghostscript.com/doc/current/API.htm#return_codes) you can find all Ghostscript errors code. 322 | 323 | ### Min and Max supported revision 324 | 325 | This module was built based on Ghostscript C API that is compatible with some specifics versions. The module has two 326 | properties **MIN_SUPPORTED_REVISION** and **MAX_SUPPORTED_REVISION** which respectively indicate the minimum and maximum supported Ghostscript's version. 327 | 328 | #### Example - Min and Max supported revision 329 | 330 | ```js 331 | 'use strict' 332 | 333 | const gs = require('ghostscript4js') 334 | 335 | console.log(gs.MIN_SUPPORTED_REVISION) 336 | console.log(gs.MAX_SUPPORTED_REVISION) 337 | 338 | ``` 339 | 340 | 341 | 342 | ## Docker 343 | 344 | Check out the example `Dockerfile` in `examples/docker`. It will create an image based on node 8.x and Debian stretch. 345 | 346 | To build the image do: 347 | 348 | 349 | ``` 350 | cd examples/docker 351 | docker build -t ghostscript4js . 352 | ``` 353 | 354 | Now you can run the image. By default it does `npm start` (which is `node index.js`) and exits. 355 | 356 | ``` 357 | docker run ghostscript4js 358 | ``` 359 | 360 | Running the container should output something like: 361 | 362 | ``` 363 | { product: 'GPL Ghostscript', 364 | copyright: 'Copyright (C) 2016 Artifex Software, Inc. All rights reserved.', 365 | revision: 920, 366 | revisiondate: 20160926 } 367 | ``` 368 | 369 | If you want to look around in the container you can get a shell like: 370 | 371 | ``` 372 | docker run -it ghostscript4js /bin/bash 373 | gs --version 374 | ``` 375 | 376 | 377 | 378 | ## The Team 379 | 380 | ### Nicola Del Gobbo 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | ### Mauro Doganieri 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | ## Acknowledgements 399 | 400 | Thank you to all people that encourage me every day. 401 | 402 | 403 | 404 | ## License 405 | 406 | Licensed under [Apache license V2](./LICENSE) 407 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "ghostscript4js", 5 | "sources": ["src/ghostscript4js.cc"], 6 | 'cflags!': [ '-fno-exceptions' ], 7 | 'cflags_cc!': [ '-fno-exceptions' ], 8 | "include_dirs": [ 9 | " (https://www.prinzhorn.it/)", 11 | "license": "Apache-2.0", 12 | "private": true, 13 | "dependencies": { 14 | "ghostscript4js": "^2.0.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gs4js-env-dll.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict' 21 | 22 | let GS4JS_DLL = "" 23 | if (process.env.GS4JS_DLL) { 24 | GS4JS_DLL = process.env.GS4JS_DLL 25 | GS4JS_DLL = GS4JS_DLL.split("\\").join("/") 26 | } 27 | process.stdout.write(GS4JS_DLL) 28 | -------------------------------------------------------------------------------- /gs4js-env-home.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict' 21 | 22 | let GS4JS_HOME = "" 23 | if (process.env.GS4JS_HOME) { 24 | GS4JS_HOME = process.env.GS4JS_HOME 25 | GS4JS_HOME = GS4JS_HOME.split("\\").join("/") 26 | } 27 | process.stdout.write(GS4JS_HOME) 28 | -------------------------------------------------------------------------------- /gs4js-env-lib.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict' 21 | 22 | let GS4JS_LIB = "" 23 | if (process.env.GS4JS_LIB) { 24 | GS4JS_LIB = process.env.GS4JS_LIB 25 | GS4JS_LIB = GS4JS_LIB.split("\\").join("/") 26 | } 27 | process.stdout.write(GS4JS_LIB) 28 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict' 21 | 22 | module.exports = require('./lib') 23 | -------------------------------------------------------------------------------- /lib/ghostscript4js.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict' 21 | 22 | /*! 23 | * Module dependencies 24 | */ 25 | const gs = require('bindings')('ghostscript4js') 26 | 27 | module.exports = { 28 | 29 | MAX_SUPPORTED_REVISION: 950, 30 | 31 | MIN_SUPPORTED_REVISION: 919, 32 | 33 | version() { 34 | return gs.version() 35 | }, 36 | 37 | execute(cmd, callback) { 38 | if (!callback) { 39 | return new Promise((resolve, reject) => { 40 | gs.execute(cmd, (err) => { 41 | if (err) { 42 | reject(err) 43 | } 44 | resolve() 45 | }) 46 | }); 47 | } else { 48 | if (typeof callback !== 'function') { 49 | throw new TypeError('Parameter callback must be a function') 50 | } 51 | return gs.execute(cmd, callback) 52 | } 53 | }, 54 | 55 | executeSync(cmd) { 56 | return gs.executeSync(cmd) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict' 21 | 22 | module.exports = require('./ghostscript4js') -------------------------------------------------------------------------------- /macOS-lib-path-finder.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { promisify } = require('util') 4 | const exec = promisify(require('child_process').exec) 5 | const {stat} = require('fs').promises 6 | const path = require('path') 7 | 8 | 9 | const LIBRARY = 'libgs.dylib' 10 | const SYSTEM_PATH = '/usr/local/lib' 11 | 12 | const isLibraryExists = async (libraryPath) => { 13 | try { 14 | await stat(libraryPath) 15 | return true 16 | } catch (err) { 17 | return false 18 | } 19 | } 20 | 21 | const isInstalled = async (command) => { 22 | try { 23 | await exec(`which ${command}`) 24 | return true 25 | } catch (err) { 26 | return false 27 | } 28 | 29 | } 30 | 31 | 32 | async function main() { 33 | try { 34 | let isGSExists = false 35 | isGSExists = await isLibraryExists(path.join(SYSTEM_PATH, LIBRARY)) 36 | if (isGSExists) { 37 | process.stdout.write(SYSTEM_PATH) 38 | return 39 | } else { 40 | if (!await isInstalled('brew')) { 41 | return 1 42 | } 43 | if (!await isInstalled('gs')) { 44 | return 1 45 | } 46 | const cellarPath = (await exec('brew --cellar')).stdout 47 | const gsVersion = (await exec('gs --version')).stdout 48 | const gsLibraryPath = path.join(cellarPath.trim(), 'ghostscript', gsVersion.trim(), 'lib') 49 | isGSExists = await isLibraryExists(path.join(gsLibraryPath, LIBRARY)) 50 | 51 | if (isGSExists) { 52 | process.stdout.write(gsLibraryPath) 53 | return 54 | } else { 55 | return 1 56 | } 57 | } 58 | } catch (err) { 59 | process.emitWarning(err) 60 | return 1 61 | } 62 | 63 | } 64 | 65 | main() -------------------------------------------------------------------------------- /node-love-ghostscript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NickNaso/ghostscript4js/1b06fe0aa2076b1a7ef9765e6d67daa0e4c87634/node-love-ghostscript.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ghostscript4js", 3 | "description": "Bindings for the Ghostscript C API to the Node.JS world.", 4 | "version": "3.2.3", 5 | "contributors": [ 6 | { 7 | "name": "Nicola Del Gobbo", 8 | "email": "nicoladelgobbo@gmail.com" 9 | }, 10 | { 11 | "name": "Mauro Doganieri", 12 | "email": "mauro.doganieri@gmail.com" 13 | }, 14 | { 15 | "name": "Alexander Prinzhorn", 16 | "email": "alexander@prinzhorn.it" 17 | }, 18 | { 19 | "name": "Eric Semeniuc", 20 | "url": "https://github.com/esemeniuc" 21 | }, 22 | { 23 | "name": "George Gershevich", 24 | "email": "george.gershevich@gmail.com" 25 | }, 26 | { 27 | "name": "Loren Yu", 28 | "email": "loren@navapbc.com" 29 | }, 30 | { 31 | "name": "Samuel Bronson", 32 | "url": "https://github.com/SamB" 33 | } 34 | ], 35 | "keywords": [ 36 | "ghostscript", 37 | "postscript", 38 | "native", 39 | "pdf", 40 | "ps", 41 | "eps" 42 | ], 43 | "license": "Apache-2.0", 44 | "scripts": { 45 | "test": "node node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=test/jasmine.json", 46 | "debug": "node-gyp rebuild --debug" 47 | }, 48 | "engines": { 49 | "node": ">= 6.0.0" 50 | }, 51 | "gypfile": true, 52 | "repository": { 53 | "type": "git", 54 | "url": "https://github.com/NickNaso/ghostscript4js.git" 55 | }, 56 | "bugs": { 57 | "url": "https://github.com/NickNaso/ghostscript4js/issues" 58 | }, 59 | "homepage": "http://www.nacios.it/", 60 | "dependencies": { 61 | "bindings": "^1.5.0", 62 | "node-addon-api": "^2.0.0" 63 | }, 64 | "devDependencies": { 65 | "jasmine": "^3.5.0" 66 | }, 67 | "main": "./index.js", 68 | "files": [ 69 | "LICENSE", 70 | "README.md", 71 | "CHANGELOG.md", 72 | "CODE_OF_CONDUCT.md", 73 | "binding.gyp", 74 | "index.js", 75 | "gs4js-env-home.js", 76 | "gs4js-env-lib.js", 77 | "gs4js-env-dll.js", 78 | "macOS-lib-path-finder.js", 79 | "binding.gyp", 80 | "lib/", 81 | "src/" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /src/ghostscript4js.cc: -------------------------------------------------------------------------------- 1 | /* ****************************************************************************** 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | #include "ghostscript4js.h" 21 | 22 | // Lifeclycle management for the Ghostscript instance 23 | class GhostscriptManager 24 | { 25 | private: 26 | void *minst; 27 | mutex gs; 28 | static GhostscriptManager *instance; 29 | GhostscriptManager() 30 | { 31 | minst = nullptr; 32 | } 33 | void Init(); 34 | void Destroy(); 35 | void Exit(); 36 | 37 | public: 38 | static GhostscriptManager *GetInstance(); 39 | ~GhostscriptManager() 40 | { 41 | minst = nullptr; 42 | }; 43 | void Execute(int gsargc, char *gsargv[]); 44 | }; 45 | 46 | GhostscriptManager *GhostscriptManager::instance = nullptr; 47 | // Static method that create or simple return the instance of the GhostscriptManager 48 | // following the singleton design pattern 49 | GhostscriptManager *GhostscriptManager::GetInstance() 50 | { 51 | if (instance == nullptr) 52 | { 53 | instance = new GhostscriptManager(); 54 | } 55 | return instance; 56 | } 57 | 58 | // Init is an implementation of gsapi_new_instance. 59 | // It returns a global static instance of Ghostscript. 60 | // i.e. Do not call init more than once, otherwise an error will be returned. 61 | void GhostscriptManager::Init() 62 | { 63 | int code = 0; 64 | code = gsapi_new_instance(&minst, NULL); 65 | if (code < 0) 66 | { 67 | throw std::runtime_error("Sorry error happened creating Ghostscript instance. Error code: " + to_string(code)); 68 | } 69 | code = gsapi_set_arg_encoding(minst, GS_ARG_ENCODING_UTF8); 70 | if (code < 0) 71 | { 72 | throw std::runtime_error("Sorry error happened in setting the encoding for Ghostscript interpreter. Error code: " + to_string(code)); 73 | } 74 | } 75 | 76 | // Execute is an implementation of gsapi_init_with_args. 77 | // It initialises the Ghostscript interpreter given a set of arguments. 78 | void GhostscriptManager::Execute(int gsargc, char *gsargv[]) 79 | { 80 | lock_guard lk(gs); 81 | Init(); 82 | int code = 0; 83 | code = gsapi_init_with_args(minst, gsargc, gsargv); 84 | Exit(); 85 | Destroy(); 86 | if (code < 0 && code != gs_error_Quit) 87 | { 88 | throw std::runtime_error("Sorry error happened executing Ghostscript command. Error code: " + to_string(code)); 89 | } 90 | } 91 | 92 | 93 | // Exit is an implementation of gsapi_exit. 94 | // It exits the Ghostscript interpreter. 95 | // It must be called if init has been called, and just before destroy. 96 | void GhostscriptManager::Exit() 97 | { 98 | int code = 0; 99 | code = gsapi_exit(minst); 100 | if (code < 0 && code != gs_error_Quit) 101 | { 102 | throw std::runtime_error("Sorry error happened during the exit from the Ghostscript interpreter. Error code: " + to_string(code)); 103 | } 104 | } 105 | 106 | // Destroy is an implementation of gsapi_delete_instance. 107 | // It destroys a global static instance of Ghostscript. 108 | // It should be called only after exit has been called if init has been called. 109 | void GhostscriptManager::Destroy() 110 | { 111 | gsapi_delete_instance(minst); 112 | minst = nullptr; 113 | } 114 | 115 | class GhostscriptWorker : public Napi::AsyncWorker 116 | { 117 | public: 118 | GhostscriptWorker(Napi::Function& callback, vector explodedCmd) 119 | : Napi::AsyncWorker(callback, "ghostcript4js"), explodedCmd(explodedCmd) {} 120 | ~GhostscriptWorker() {} 121 | 122 | void Execute() 123 | { 124 | int gsargc = static_cast(explodedCmd.size()); 125 | char **gsargv = new char *[gsargc]; 126 | for (int i = 0; i < gsargc; i++) 127 | { 128 | gsargv[i] = (char *)explodedCmd[i].c_str(); 129 | } 130 | try 131 | { 132 | GhostscriptManager *gm = GhostscriptManager::GetInstance(); 133 | gm->Execute(gsargc, gsargv); 134 | delete[] gsargv; 135 | } 136 | catch (exception &e) 137 | { 138 | delete[] gsargv; 139 | SetError(e.what()); 140 | } 141 | } 142 | 143 | void OnOk() 144 | { 145 | Napi::HandleScope scope(Env()); 146 | Callback().Call({Env().Null()}); 147 | } 148 | 149 | private: 150 | vector explodedCmd; 151 | }; 152 | 153 | Napi::Value Version(const Napi::CallbackInfo& info) { 154 | Napi::Env env = info.Env(); 155 | Napi::Object obj = Napi::Object::New(env); 156 | gsapi_revision_t r; 157 | int res = gsapi_revision(&r, sizeof(r)); 158 | if (res == 0) { 159 | obj["product"] = Napi::String::New(env, r.product); 160 | obj["copyright"] = Napi::String::New(env, r.copyright); 161 | obj["revision"] = Napi::Number::New(env, r.revision); 162 | obj["revisiondate"] = Napi::Number::New(env, r.revisiondate); 163 | } else { 164 | std::stringstream msg; 165 | msg << "Sorry error happened retrieving Ghostscript version info. Error code: " << res; 166 | throw Napi::Error::New(env, msg.str()); 167 | } 168 | return obj; 169 | } 170 | 171 | vector ConvertArguments(const Napi::CallbackInfo& info) { 172 | Napi::Env env = info.Env(); 173 | if (info.Length() < 1) 174 | { 175 | throw Napi::Error::New(env, "Sorry method requires 1 argument that represent the Ghostscript command."); 176 | } 177 | if (!info[0].IsString() && !info[0].IsArray()) 178 | { 179 | throw Napi::Error::New(env, "Sorry method's argument should be a string or an array of strings"); 180 | } 181 | vector explodedCmd; 182 | if (info[0].IsString()) 183 | { 184 | string RAWcmd = info[0].As().Utf8Value(); 185 | istringstream iss(RAWcmd); 186 | for (string RAWcmd; iss >> RAWcmd;) 187 | explodedCmd.push_back(RAWcmd); 188 | } 189 | if (info[0].IsArray()) 190 | { 191 | Napi::Array array = info[0].As(); 192 | for (uint32_t i = 0; i < array.Length(); i++) 193 | { 194 | Napi::Value value = array[i]; 195 | if (!value.IsString()) 196 | { 197 | throw Napi::Error::New(env, "Sorry method's argument should be a string or an array of strings"); 198 | } 199 | string RAWcmd = value.As().Utf8Value(); 200 | explodedCmd.push_back(RAWcmd); 201 | } 202 | } 203 | return explodedCmd; 204 | } 205 | 206 | void Execute(const Napi::CallbackInfo& info) { 207 | vector explodedCmd = ConvertArguments(info); 208 | Napi::Function callback = info[1].As(); 209 | GhostscriptWorker* gs = new GhostscriptWorker(callback, explodedCmd); 210 | gs->Queue(); 211 | } 212 | 213 | void ExecuteSync(const Napi::CallbackInfo& info) 214 | { 215 | Napi::Env env = info.Env(); 216 | vector explodedCmd = ConvertArguments(info); 217 | int gsargc = static_cast(explodedCmd.size()); 218 | char **gsargv = new char *[gsargc]; 219 | for (int i = 0; i < gsargc; i++) 220 | { 221 | gsargv[i] = (char *)explodedCmd[i].c_str(); 222 | } 223 | try 224 | { 225 | GhostscriptManager *gm = GhostscriptManager::GetInstance(); 226 | 227 | gm->Execute(gsargc, gsargv); 228 | delete[] gsargv; 229 | } 230 | catch (exception &e) 231 | { 232 | delete[] gsargv; 233 | throw Napi::Error::New(env, e.what()); 234 | } 235 | } 236 | 237 | //////////////////////////// INIT & CONFIG MODULE ////////////////////////////// 238 | 239 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 240 | exports.Set(Napi::String::New(env, "version"), Napi::Function::New(env, Version)); 241 | exports.Set(Napi::String::New(env, "execute"), Napi::Function::New(env, Execute)); 242 | exports.Set(Napi::String::New(env, "executeSync"), Napi::Function::New(env, ExecuteSync)); 243 | return exports; 244 | } 245 | 246 | NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) 247 | 248 | //////////////////////////////////////////////////////////////////////////////// 249 | -------------------------------------------------------------------------------- /src/ghostscript4js.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | #ifndef GHOSTSCRIPT4JS_H 21 | #define GHOSTSCRIPT4JS_H 22 | 23 | #if defined(_WIN32) && !defined(_Windows) 24 | #define _Windows 25 | #endif 26 | #ifdef _Windows 27 | //#define _WINSOCKAPI_ 28 | //#include 29 | #define GSDLLEXPORT __declspec(dllimport) 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #include "iapi.h" 40 | 41 | #define gs_error_Quit -101 42 | 43 | //using namespace Napi; 44 | using namespace std; 45 | 46 | #endif //GHOSTSCRIPT4JS_H 47 | -------------------------------------------------------------------------------- /src/iapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API for Ghostscript interpreter 3 | * for use both as DLL and for static linking. 4 | * 5 | * Should work for Windows, OS/2, Linux, Mac. 6 | * 7 | * DLL exported functions should be as similar as possible to imain.c 8 | * You will need to include "ierrors.h". 9 | * 10 | * Current problems: 11 | * 1. Ghostscript does not support multiple instances. 12 | * 2. Global variables in gs_main_instance_default() 13 | * and gsapi_instance_counter 14 | */ 15 | 16 | /* Exported functions may need different prefix 17 | * GSDLLEXPORT marks functions as exported 18 | * GSDLLAPI is the calling convention used on functions exported 19 | * by Ghostscript 20 | * GSDLLCALL is used on callback functions called by Ghostscript 21 | * When you include this header file in the caller, you may 22 | * need to change the definitions by defining these 23 | * before including this header file. 24 | * Make sure you get the calling convention correct, otherwise your 25 | * program will crash either during callbacks or soon after returning 26 | * due to stack corruption. 27 | */ 28 | 29 | #ifndef iapi_INCLUDED 30 | # define iapi_INCLUDED 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #if defined(_WINDOWS_) || defined(__WINDOWS__) 37 | # ifndef _Windows 38 | # define _Windows 39 | # endif 40 | #endif 41 | 42 | #ifdef _Windows 43 | # ifndef GSDLLEXPORT 44 | /* We don't need both the "__declspec(dllexport)" declaration 45 | * and the listing in the .def file - having both results in 46 | * a linker warning on x64 builds (but is incorrect on x86, too) 47 | */ 48 | # if 0 49 | # define GSDLLEXPORT __declspec(dllexport) 50 | # else 51 | # define GSDLLEXPORT 52 | # endif 53 | # endif 54 | # ifndef GSDLLAPI 55 | # define GSDLLAPI __stdcall 56 | # endif 57 | # ifndef GSDLLCALL 58 | # define GSDLLCALL __stdcall 59 | # endif 60 | #endif /* _Windows */ 61 | 62 | #if defined(OS2) && defined(__IBMC__) 63 | # ifndef GSDLLAPI 64 | # define GSDLLAPI _System 65 | # endif 66 | # ifndef GSDLLCALL 67 | # define GSDLLCALL _System 68 | # endif 69 | #endif /* OS2 && __IBMC */ 70 | 71 | #ifdef __MACOS__ 72 | # pragma export on 73 | #endif 74 | 75 | #ifndef GSDLLEXPORT 76 | # define GSDLLEXPORT 77 | #endif 78 | #ifndef GSDLLAPI 79 | # define GSDLLAPI 80 | #endif 81 | #ifndef GSDLLCALL 82 | # define GSDLLCALL 83 | #endif 84 | 85 | #if defined(__IBMC__) 86 | # define GSDLLAPIPTR * GSDLLAPI 87 | # define GSDLLCALLPTR * GSDLLCALL 88 | #else 89 | # define GSDLLAPIPTR GSDLLAPI * 90 | # define GSDLLCALLPTR GSDLLCALL * 91 | #endif 92 | 93 | #ifndef display_callback_DEFINED 94 | # define display_callback_DEFINED 95 | typedef struct display_callback_s display_callback; 96 | #endif 97 | 98 | typedef struct gsapi_revision_s { 99 | const char *product; 100 | const char *copyright; 101 | long revision; 102 | long revisiondate; 103 | } gsapi_revision_t; 104 | 105 | /* Get version numbers and strings. 106 | * This is safe to call at any time. 107 | * You should call this first to make sure that the correct version 108 | * of the Ghostscript is being used. 109 | * pr is a pointer to a revision structure. 110 | * len is the size of this structure in bytes. 111 | * Returns 0 if OK, or if len too small (additional parameters 112 | * have been added to the structure) it will return the required 113 | * size of the structure. 114 | */ 115 | GSDLLEXPORT int GSDLLAPI 116 | gsapi_revision(gsapi_revision_t *pr, int len); 117 | 118 | /* 119 | * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 120 | * Ghostscript supports only one instance. 121 | * The current implementation uses a global static instance 122 | * counter to make sure that only a single instance is used. 123 | * If you try to create two instances, the second attempt 124 | * will return < 0 and set pinstance to NULL. 125 | * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 126 | */ 127 | /* Create a new instance of Ghostscript. 128 | * This instance is passed to most other API functions. 129 | * The caller_handle will be provided to callback functions. 130 | */ 131 | 132 | GSDLLEXPORT int GSDLLAPI 133 | gsapi_new_instance(void **pinstance, void *caller_handle); 134 | 135 | /* 136 | * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 137 | * Ghostscript supports only one instance. 138 | * The current implementation uses a global static instance 139 | * counter to make sure that only a single instance is used. 140 | * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 141 | */ 142 | /* Destroy an instance of Ghostscript 143 | * Before you call this, Ghostscript must have finished. 144 | * If Ghostscript has been initialised, you must call gsapi_exit() 145 | * before gsapi_delete_instance. 146 | */ 147 | GSDLLEXPORT void GSDLLAPI 148 | gsapi_delete_instance(void *instance); 149 | 150 | /* Set the encoding used for the args. By default we assume 151 | * 'local' encoding. For windows this equates to whatever the current 152 | * codepage is. For linux this is utf8. 153 | * 154 | * Use of this API (gsapi) with 'local' encodings (and hence without calling 155 | * this function) is now deprecated! 156 | */ 157 | GSDLLEXPORT int GSDLLAPI gsapi_set_arg_encoding(void *instance, 158 | int encoding); 159 | 160 | enum { 161 | GS_ARG_ENCODING_LOCAL = 0, 162 | GS_ARG_ENCODING_UTF8 = 1, 163 | GS_ARG_ENCODING_UTF16LE = 2 164 | }; 165 | 166 | /* Initialise the interpreter. 167 | * This calls gs_main_init_with_args() in imainarg.c 168 | * 1. If quit or EOF occur during gsapi_init_with_args(), 169 | * the return value will be gs_error_Quit. This is not an error. 170 | * You must call gsapi_exit() and must not call any other 171 | * gsapi_XXX functions. 172 | * 2. If usage info should be displayed, the return value will be gs_error_Info 173 | * which is not an error. Do not call gsapi_exit(). 174 | * 3. Under normal conditions this returns 0. You would then 175 | * call one or more gsapi_run_*() functions and then finish 176 | * with gsapi_exit(). 177 | */ 178 | GSDLLEXPORT int GSDLLAPI gsapi_init_with_args(void *instance, 179 | int argc, char **argv); 180 | 181 | /* Exit the interpreter. 182 | * This must be called on shutdown if gsapi_init_with_args() 183 | * has been called, and just before gsapi_delete_instance(). 184 | */ 185 | GSDLLEXPORT int GSDLLAPI 186 | gsapi_exit(void *instance); 187 | 188 | /* function prototypes */ 189 | typedef int (GSDLLAPIPTR PFN_gsapi_revision)( 190 | gsapi_revision_t *pr, int len); 191 | typedef int (GSDLLAPIPTR PFN_gsapi_new_instance)( 192 | void **pinstance, void *caller_handle); 193 | typedef void (GSDLLAPIPTR PFN_gsapi_delete_instance)( 194 | void *instance); 195 | typedef int (GSDLLAPIPTR PFN_gsapi_init_with_args)( 196 | void *instance, int argc, char **argv); 197 | typedef int (GSDLLAPIPTR PFN_gsapi_set_arg_encoding)( 198 | void *instance, int encoding); 199 | typedef int (GSDLLAPIPTR PFN_gsapi_exit)(void *instance); 200 | 201 | #ifdef __MACOS__ 202 | #pragma export off 203 | #endif 204 | 205 | #ifdef __cplusplus 206 | } /* extern 'C' protection */ 207 | #endif 208 | 209 | #endif /* iapi_INCLUDED */ 210 | -------------------------------------------------------------------------------- /test/ghostscript4js.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017 Nicola Del Gobbo 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | * use this file except in compliance with the License. You may obtain a copy of 5 | * the license at http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS 8 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 9 | * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | * MERCHANTABLITY OR NON-INFRINGEMENT. 11 | * 12 | * See the Apache Version 2.0 License for specific language governing 13 | * permissions and limitations under the License. 14 | * 15 | * Contributors - initial API implementation: 16 | * Nicola Del Gobbo 17 | * Mauro Doganieri 18 | ******************************************************************************/ 19 | 20 | 'use strict'; 21 | 22 | /*! 23 | * Module dependencies 24 | */ 25 | const gs = require('../') 26 | const fs = require('fs') 27 | 28 | process.chdir(__dirname) 29 | 30 | const pdf = 'node-love-ghostscript.pdf' 31 | // Invalid PDF file by taking a text file with Lorem ipsum text and renaming to have .pdf extension 32 | const pdfInvalid = 'invalid.pdf' 33 | const ps = 'node-love-ghostscript.ps' 34 | const pngSync = 'node-love-ghostscript-sync.png' 35 | const pngAsync = 'node-love-ghostscript-async.png' 36 | const pngSyncArray = 'node love ghostscript sync.png' 37 | const pngAsyncArray = 'node love ghostscript async.png' 38 | const pdfSync = 'node-love-ghostscript-sync.pdf' 39 | const pdfAsync = 'node-love-ghostscript-async.pdf' 40 | const pdfSyncArray = 'node love ghostscript sync.pdf' 41 | const pdfAsyncArray = 'node love ghostscript async.pdf' 42 | 43 | const cmdSyncPng = `-psconv -q -dNOPAUSE -sDEVICE=pngalpha -o ${pngSync} -sDEVICE=pngalpha -r144 ${pdf}` 44 | const cmdAsyncPng = `-psconv -q -dNOPAUSE -sDEVICE=pngalpha -o ${pngAsync} -sDEVICE=pngalpha -r144 ${pdf}` 45 | const cmdSyncPngArray = ['-psconv', '-q', '-dNOPAUSE', '-sDEVICE=pngalpha', '-o', `${pngSyncArray}`, '-sDEVICE=pngalpha', '-r144', `${pdf}`] 46 | const cmdAsyncPngArray = ['-psconv', '-q', '-dNOPAUSE', '-sDEVICE=pngalpha', '-o', `${pngAsyncArray}`, '-sDEVICE=pngalpha', '-r144', `${pdf}`] 47 | 48 | const cmdInvalidPdf = `-q -dNOPAUSE -sDEVICE=jpeg -o test/out-%02d.jpg -r144 ${pdfInvalid}` 49 | const cmdSyncPdf = `-psconv -q -dNOPAUSE -sDEVICE=pdfwrite -o ${pdfSync} -f ${ps}` 50 | const cmdAsyncPdf = `-psconv -q -dNOPAUSE -sDEVICE=pdfwrite -o ${pdfAsync} -f ${ps}` 51 | const cmdSyncPdfArray = ['-psconv', '-q', '-dNOPAUSE', '-sDEVICE=pdfwrite', '-o', `${pdfSyncArray}`, '-f', `${ps}`] 52 | const cmdAsyncPdfArray = ['-psconv', '-q', '-dNOPAUSE', '-sDEVICE=pdfwrite', '-o', `${pdfAsyncArray}`, '-f', `${ps}`] 53 | 54 | 55 | function cleanup() { 56 | console.log('Start cleanup ...') 57 | try { 58 | fs.unlinkSync(pngSync) 59 | fs.unlinkSync(pngAsync) 60 | fs.unlinkSync(pdfSync) 61 | fs.unlinkSync(pdfAsync) 62 | fs.unlinkSync(pngSyncArray) 63 | fs.unlinkSync(pngAsyncArray) 64 | fs.unlinkSync(pdfSyncArray) 65 | fs.unlinkSync(pdfAsyncArray) 66 | console.log('Cleanup competed') 67 | } catch (err) { 68 | console.log('Nothing to clean'); 69 | } 70 | } 71 | 72 | describe('Test ghostscript4js', function () { 73 | 74 | beforeAll(cleanup) 75 | 76 | it('Should return the version of Ghoscript', function () { 77 | expect(gs.version).not.toThrow() 78 | const version = gs.version() 79 | expect(version.product).toContain('GPL Ghostscript') 80 | expect(version.copyright).toContain('Copyright (C)') 81 | expect(version.copyright).toContain('Artifex Software, Inc. All rights reserved.') 82 | expect(version.product).not.toBeLessThan(gs.MIN_SUPPORTED_REVISION) 83 | expect(version.product).not.toBeLessThan(20160323) 84 | }) 85 | 86 | it('Should execute Ghostscript command synchronous', function () { 87 | const executeSync = async function execute() { 88 | return gs.executeSync(cmdSyncPng) 89 | } 90 | expect(executeSync).not.toThrow() 91 | }) 92 | 93 | it('Should execute Ghostscript command synchronous with array based API', function () { 94 | const executeSync = async function execute() { 95 | return gs.executeSync(cmdSyncPngArray) 96 | } 97 | expect(executeSync).not.toThrow() 98 | }) 99 | 100 | it('Should execute Ghostscript command synchronous without parameters and fail with error', function () { 101 | expect(gs.executeSync).toThrowError('Sorry method\'s argument should be a string or an array of strings'); 102 | }) 103 | 104 | it('Should execute Ghostscript command asynchronous', async function () { 105 | const execute = async function execute() { 106 | return gs.execute(cmdAsyncPng) 107 | } 108 | await expectAsync(execute()).not.toBeRejected() 109 | await expectAsync(execute()).toBeResolved() 110 | }) 111 | 112 | it('Should execute Ghostscript command asynchronous with array based API', async function () { 113 | const execute = async function execute() { 114 | return gs.execute(cmdAsyncPngArray) 115 | } 116 | await expectAsync(execute()).not.toBeRejected() 117 | await expectAsync(execute()).toBeResolved() 118 | }) 119 | 120 | it('Should execute Ghostscript command synchronous', function () { 121 | const executeSync = async function execute() { 122 | return gs.executeSync(cmdSyncPdf) 123 | } 124 | expect(executeSync).not.toThrow() 125 | }) 126 | 127 | it('Should execute Ghostscript command synchronous with array based API', function () { 128 | const executeSync = async function execute() { 129 | return gs.executeSync(cmdSyncPdfArray) 130 | } 131 | expect(executeSync).not.toThrow() 132 | }) 133 | 134 | it('Should execute Ghostscript command asynchronous', async function () { 135 | const execute = async function execute() { 136 | return gs.execute(cmdAsyncPdf) 137 | } 138 | await expectAsync(execute()).not.toBeRejected() 139 | await expectAsync(execute()).toBeResolved() 140 | }) 141 | 142 | it('Should execute Ghostscript command asynchronous with array based API', async function () { 143 | const execute = async function execute() { 144 | return gs.execute(cmdAsyncPdfArray) 145 | } 146 | await expectAsync(execute()).not.toBeRejected() 147 | await expectAsync(execute()).toBeResolved() 148 | }) 149 | 150 | it('Should throw an error if ghostscript command returns nonzero exit code', async function () { 151 | const execute = async function execute() { 152 | return gs.execute(cmdInvalidPdf) 153 | } 154 | await expectAsync(execute()).toBeRejected() 155 | await expectAsync(execute()).not.toBeResolved() 156 | await expectAsync(execute()).toBeRejectedWithError('Sorry error happened executing Ghostscript command. Error code: -100') 157 | }) 158 | 159 | it('Should execute Ghostscript command asynchronous without parameters and fail', async function () { 160 | const execute = async function execute() { 161 | return gs.execute() 162 | } 163 | await expectAsync(execute()).toBeRejected() 164 | await expectAsync(execute()).not.toBeResolved() 165 | await expectAsync(execute()).toBeRejectedWithError('Sorry method\'s argument should be a string or an array of strings') 166 | }) 167 | 168 | afterAll(cleanup) 169 | 170 | }) -------------------------------------------------------------------------------- /test/invalid.pdf: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultricies ornare tortor vel imperdiet. Fusce mattis turpis non nisi convallis facilisis. Maecenas mollis mi nec ex tempus, in sollicitudin diam viverra. Praesent sodales consectetur elit a posuere. Sed finibus euismod sem, sed semper purus gravida non. Quisque mattis volutpat tempor. Sed eget ante luctus, finibus magna id, fringilla erat. Mauris faucibus euismod facilisis. Integer mollis ut ex sit amet scelerisque. Fusce hendrerit ultricies congue. 2 | 3 | Nullam ultricies, massa ut placerat sollicitudin, quam ipsum porta erat, ac pulvinar nisl orci quis odio. Phasellus scelerisque auctor neque, sed malesuada neque laoreet et. Etiam a ipsum in turpis tincidunt consectetur. Morbi velit ex, sodales sit amet ornare a, laoreet ac est. Nunc nec ligula a eros gravida tincidunt sit amet egestas eros. Aenean in arcu a neque aliquam consectetur. Maecenas sagittis ligula dolor, et malesuada dui rutrum nec. In sodales sollicitudin aliquet. Nam imperdiet ultricies metus, eget pellentesque quam facilisis vel. Sed tempor eu dolor ac aliquet. 4 | 5 | Maecenas nibh massa, rutrum in nulla in, commodo efficitur nisi. Duis nec odio sapien. Morbi placerat molestie leo, at pretium urna. Nullam ut lacinia felis, eu egestas metus. Pellentesque vitae efficitur arcu, quis sodales ante. In malesuada rhoncus dui vel ornare. Sed ultrices, neque eu laoreet accumsan, urna libero porttitor ante, et tincidunt ipsum ipsum ut elit. Cras volutpat placerat tincidunt. Duis ante tellus, iaculis ut ex quis, bibendum tincidunt libero. 6 | 7 | Praesent dictum ultricies quam, egestas pellentesque purus molestie et. Suspendisse tristique blandit massa, varius laoreet ex elementum ut. Ut nibh nunc, egestas sed dolor ac, tincidunt scelerisque quam. Mauris ultricies libero vitae leo maximus malesuada. Pellentesque orci elit, dignissim sed sagittis at, placerat et augue. Duis a convallis tortor. Duis vulputate facilisis arcu quis finibus. Vestibulum diam lectus, euismod sed tempor nec, rutrum vel risus. Nunc auctor pharetra enim, a viverra lectus mattis a. Aenean vestibulum gravida dictum. Curabitur gravida, magna et tincidunt pellentesque, lectus lectus pharetra lacus, ut fermentum nibh elit eu augue. Vivamus scelerisque velit massa, sit amet ullamcorper nisi posuere id. Vestibulum sapien elit, malesuada sit amet mauris non, rutrum tincidunt metus. 8 | 9 | Vestibulum quis cursus libero, id faucibus odio. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris mollis feugiat enim eu tempus. Sed mattis nibh nec lacus condimentum venenatis. Aenean a molestie risus. Proin varius orci turpis, ac vehicula risus bibendum vel. Suspendisse potenti. Morbi gravida blandit orci nec ullamcorper. Phasellus eu metus vitae lacus bibendum luctus vel cursus sapien. Quisque finibus imperdiet scelerisque. Donec vitae dolor eros. Aliquam erat volutpat. 10 | -------------------------------------------------------------------------------- /test/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test", 3 | "spec_files": [ 4 | "ghostscript4js.js" 5 | ], 6 | "helpers": [] 7 | } -------------------------------------------------------------------------------- /test/node-love-ghostscript.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NickNaso/ghostscript4js/1b06fe0aa2076b1a7ef9765e6d67daa0e4c87634/test/node-love-ghostscript.pdf -------------------------------------------------------------------------------- /test/node-love-ghostscript.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-2.0 2 | %%Creator: dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software 3 | %%Title: 26policy.dvi 4 | %%Pages: 2 5 | %%PageOrder: Ascend 6 | %%BoundingBox: 0 0 612 792 7 | %%DocumentPaperSizes: Letter 8 | %%EndComments 9 | %DVIPSCommandLine: dvips -o 26policy.ps 26policy 10 | %DVIPSParameters: dpi=300, comments removed 11 | %DVIPSSource: TeX output 1999.02.24:1138 12 | %%BeginProcSet: tex.pro 13 | /TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N 14 | /X{S N}B /TR{translate}N /isls false N /vsize 11 72 mul N /hsize 8.5 72 15 | mul N /landplus90{false}def /@rigin{isls{[0 landplus90{1 -1}{-1 1} 16 | ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale 17 | isls{landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div 18 | hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul 19 | TR[matrix currentmatrix{dup dup round sub abs 0.00001 lt{round}if} 20 | forall round exch round exch]setmatrix}N /@landscape{/isls true N}B 21 | /@manualfeed{statusdict /manualfeed true put}B /@copies{/#copies X}B 22 | /FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{ 23 | /nn 8 dict N nn begin /FontType 3 N /FontMatrix fntrx N /FontBBox FBB N 24 | string /base X array /BitMaps X /BuildChar{CharBuilder}N /Encoding IE N 25 | end dup{/foo setfont}2 array copy cvx N load 0 nn put /ctr 0 N[}B /df{ 26 | /sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0] 27 | N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data dup 28 | length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{ 29 | 128 ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub 30 | get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data 31 | dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N 32 | /rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup 33 | /base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 34 | 0 ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff 35 | setcachedevice ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff 36 | .1 sub]{ch-image}imagemask restore}B /D{/cc X dup type /stringtype ne{]} 37 | if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{dup dup 38 | length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}B /I{ 39 | cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin 40 | 0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul 41 | add .99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore userdict 42 | /eop-hook known{eop-hook}if showpage}N /@start{userdict /start-hook 43 | known{start-hook}if pop /VResolution X /Resolution X 1000 div /DVImag X 44 | /IE 256 array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for 45 | 65781.76 div /vsize X 65781.76 div /hsize X}N /p{show}N /RMat[1 0 0 -1 0 46 | 0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X /rulex X V}B /V 47 | {}B /RV statusdict begin /product where{pop product dup length 7 ge{0 7 48 | getinterval dup(Display)eq exch 0 4 getinterval(NeXT)eq or}{pop false} 49 | ifelse}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale rulex ruley false 50 | RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR rulex ruley scale 1 1 51 | false RMat{BDot}imagemask grestore}}ifelse B /QV{gsave newpath transform 52 | round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg 53 | rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail 54 | {dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M} 55 | B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{ 56 | 4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{ 57 | p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p 58 | a}B /bos{/SS save N}B /eos{SS restore}B end 59 | %%EndProcSet 60 | TeXDict begin 40258431 52099146 1000 300 300 (26policy.dvi) 61 | @start /Fa 22 122 df<78FCFCFCFC780606778518>46 D<000300000780000F80000F 62 | 80000F00001F00001F00003E00003E00003C00007C00007C0000F80000F80000F00001F0 63 | 0001F00003E00003E00007C00007C0000780000F80000F80001F00001F00001E00003E00 64 | 003E00007C00007C0000780000F80000F80000F0000060000011247D9F18>I<78FCFCFC 65 | FC78000000000000000078FCFCFCFC780614779318>58 D<7FFFC0FFFFE0FFFFE07FFFC0 66 | 13047E7F18>95 D<0FF0001FFC003FFE003C1F0018078000038000038000FF800FFF801F 67 | FF807F8380780380F00380E00380E00380F007807C1F803FFFF81FFDF807F0F815147E93 68 | 18>97 D<01FE0007FF001FFF803F07803C0300780000700000F00000E00000E00000E000 69 | 00E00000F000007000007801C03C01C03F07C01FFF8007FF0001FC0012147D9318>99 70 | D<001F80003F80001F8000038000038000038000038000038003F3800FFB801FFF803E1F 71 | 80780F80700780F00780E00380E00380E00380E00380E00380E00780F00780700780780F 72 | 803E3F801FFFF00FFBF803E3F0151C7E9B18>I<03F0000FFC001FFE003E1F0078078070 73 | 0380F003C0E001C0E001C0FFFFC0FFFFC0FFFFC0F000007000007801C03C01C03F07C01F 74 | FF8007FF0001FC0012147D9318>I<001FC0007FE000FFE001F1E001C0C001C00001C000 75 | 01C0007FFFC0FFFFC0FFFFC001C00001C00001C00001C00001C00001C00001C00001C000 76 | 01C00001C00001C00001C00001C00001C0007FFF007FFF007FFF00131C7F9B18>I<7E00 77 | 00FE00007E00000E00000E00000E00000E00000E00000E3F000EFF800FFFC00FE1E00F80 78 | E00F00E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 79 | E07FC7FCFFE7FE7FC7FC171C809B18>104 D<038007C007C007C0038000000000000000 80 | 007FC0FFC07FC001C001C001C001C001C001C001C001C001C001C001C001C001C001C0FF 81 | FFFFFFFFFF101D7C9C18>I<7E0000FE00007E00000E00000E00000E00000E00000E0000 82 | 0E3FF00E3FF00E3FF00E07800E0F000E1E000E3C000E78000EF0000FF8000FFC000F9C00 83 | 0F1E000E0F000E07800E03800E03C07FC7F8FFC7F87FC7F8151C7F9B18>107 84 | DII<01F0000FFE001FFF003E0F803803807001C07001C0 89 | E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF000FFE00 90 | 01F00013147E9318>111 D<7E3E00FEFF807FFFC00FE3E00F80F00F00700F00780E0038 91 | 0E00380E00380E00380E00380F00380F00780F00700F80F00FC3E00FFFC00EFF800E7E00 92 | 0E00000E00000E00000E00000E00000E00000E00007FC000FFE0007FC000151E809318> 93 | I114 95 | D<0FF7003FFF007FFF00F81F00E00700E00700F007007C00007FF0001FFC0007FE00001F 96 | 00600780E00380F00380F00780FC0F00FFFF00FFFE00E7F80011147D9318>I<01800003 97 | 80000380000380000380007FFFC0FFFFC0FFFFC003800003800003800003800003800003 98 | 80000380000380000380000380400380E00380E00381E003C3C001FFC000FF80007E0013 99 | 197F9818>I<7E07E0FE0FE07E07E00E00E00E00E00E00E00E00E00E00E00E00E00E00E0 100 | 0E00E00E00E00E00E00E00E00E00E00E01E00F07E007FFFC03FFFE01FCFC1714809318> 101 | I119 103 | D<7F8FF0FF8FF87F8FF00E01C00E03800E0380070380070700070700038700038700038E 104 | 0001CE0001CE0001CC0000CC0000DC0000780000780000780000700000700000700000F0 105 | 0000E00079E0007BC0007F80003F00001E0000151E7F9318>121 106 | D E /Fb 75 123 df<001F83E000F06E3001C078780380F8780300F03007007000070070 107 | 000700700007007000070070000700700007007000FFFFFF800700700007007000070070 108 | 000700700007007000070070000700700007007000070070000700700007007000070070 109 | 000700700007007000070070000700700007007000070070003FE3FF001D20809F1B>11 110 | D<003F0000E0C001C0C00381E00701E00701E00700000700000700000700000700000700 111 | 00FFFFE00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700 112 | E00700E00700E00700E00700E00700E00700E00700E03FC3FC1620809F19>I<003FE000 113 | E0E001C1E00381E00700E00700E00700E00700E00700E00700E00700E00700E0FFFFE007 114 | 00E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E007 115 | 00E00700E00700E00700E00700E00700E03FE7FC1620809F19>I<001F81F80000F04F04 116 | 0001C07C06000380F80F000300F00F000700F00F00070070000007007000000700700000 117 | 070070000007007000000700700000FFFFFFFF0007007007000700700700070070070007 118 | 007007000700700700070070070007007007000700700700070070070007007007000700 119 | 700700070070070007007007000700700700070070070007007007000700700700070070 120 | 07003FE3FE3FE02320809F26>I<70F8F8F8F8F8F8F87070707070707070707020202020 121 | 20000000000070F8F8F87005217CA00D>33 D<7038F87CFC7EFC7E743A04020402040208 122 | 04080410081008201040200F0E7F9F17>I<078000180018400038003020003000301800 123 | F000601703E0006008FCC000E00801C000E008038000E008030000E008070000E0080E00 124 | 00E0080C000060081C00006010380000301030000030207000001840E000000780C00000 125 | 0001C078000001818400000383020000070301000006070100000E060100001C0E008000 126 | 180E008000380E008000700E008000600E008000E00E008001C00E008001800601000380 127 | 070100070003010006000302000E000184000C0000780021257EA126>37 128 | D<70F8FCFC74040404080810102040060E7C9F0D>39 D<0040008001000300060004000C 129 | 001800180038003000300070006000600060006000E000E000E000E000E000E000E000E0 130 | 00E000E000E000E00060006000600060007000300030003800180018000C000400060003 131 | 000100008000400A2E7BA112>I<8000400020003000180008000C000600060007000300 132 | 03000380018001800180018001C001C001C001C001C001C001C001C001C001C001C001C0 133 | 01800180018001800380030003000700060006000C000800180030002000400080000A2E 134 | 7EA112>I<70F0F8F878080808101010202040050E7C840D>44 D 135 | I<70F8F8F87005057C840D>I<0000C00000C00001C00001800001800003800003000007 136 | 00000600000600000E00000C00000C00001C000018000038000030000030000070000060 137 | 0000600000E00000C00001C0000180000180000380000300000300000700000600000E00 138 | 000C00000C00001C0000180000180000380000300000700000600000600000E00000C000 139 | 00C00000122D7EA117>I<03F0000E1C001C0E0018060038070070038070038070038070 140 | 0380F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F0 141 | 03C0F003C07003807003807003807807803807001806001C0E000E1C0003F000121F7E9D 142 | 17>I<008003800F80F38003800380038003800380038003800380038003800380038003 143 | 800380038003800380038003800380038003800380038007C0FFFE0F1E7C9D17>I<03F0 144 | 000C1C00100E00200700400780800780F007C0F803C0F803C0F803C02007C00007C00007 145 | 80000780000F00000E00001C0000380000700000600000C0000180000300000600400C00 146 | 401800401000803FFF807FFF80FFFF80121E7E9D17>I<03F0000C1C00100E00200F0078 147 | 0F80780780780780380F80000F80000F00000F00001E00001C0000700007F000003C0000 148 | 0E00000F000007800007800007C02007C0F807C0F807C0F807C0F00780400780400F0020 149 | 0E00183C0007F000121F7E9D17>I<000600000600000E00000E00001E00002E00002E00 150 | 004E00008E00008E00010E00020E00020E00040E00080E00080E00100E00200E00200E00 151 | 400E00C00E00FFFFF0000E00000E00000E00000E00000E00000E00000E0000FFE0141E7F 152 | 9D17>I<1803001FFE001FFC001FF8001FE0001000001000001000001000001000001000 153 | 0011F000161C00180E001007001007800003800003800003C00003C00003C07003C0F003 154 | C0F003C0E00380400380400700200600100C0008380007E000121F7E9D17>I<007C0001 155 | 82000701000E03800C0780180780380300380000780000700000700000F1F000F21C00F4 156 | 0600F80700F80380F80380F003C0F003C0F003C0F003C0F003C07003C07003C070038038 157 | 03803807001807000C0E00061C0001F000121F7E9D17>I<4000007FFFE07FFFC07FFFC0 158 | 400080800100800100800200000400000400000800001000001000002000002000006000 159 | 00600000E00000C00001C00001C00001C00001C00003C00003C00003C00003C00003C000 160 | 03C00003C000018000131F7E9D17>I<03F0000C0C001006003003002001806001806001 161 | 806001807001807803003E03003F06001FC8000FF00003F80007FC000C7E00103F00300F 162 | 806007806001C0C001C0C000C0C000C0C000C0C000806001802001001002000C0C0003F0 163 | 00121F7E9D17>I<03F0000E18001C0C00380600380700700700700380F00380F00380F0 164 | 03C0F003C0F003C0F003C0F003C07007C07007C03807C0180BC00E13C003E3C000038000 165 | 0380000380000700300700780600780E00700C002018001070000FC000121F7E9D17>I< 166 | 70F8F8F8700000000000000000000070F8F8F87005147C930D>I<70F8F8F87000000000 167 | 00000000000070F0F8F878080808101010202040051D7C930D>I<001FE0000060180001 168 | 800600020001000400008008000040100F8020203860102070101040E0080840C0070841 169 | C00708818007048380070483800704838007048380070483800704838007048180070441 170 | C0070440C0070440E00F082070170820386310100F81E008000000040000000200001C01 171 | 8000F000600F80001FF8001E207E9F23>64 D<0001000000038000000380000003800000 172 | 07C0000007C0000007C0000009E0000009E0000009E0000010F0000010F0000010F00000 173 | 207800002078000020780000403C0000403C0000C03E0000801E0000801E0001FFFF0001 174 | 000F0001000F00020007800200078002000780040003C0040003C00C0003C01E0003E0FF 175 | 801FFE1F207F9F22>II<000FE0 179 | 1000381C3000E0027003C00170078000F00F0000701E0000701E0000303C0000303C0000 180 | 107C00001078000010F8000000F8000000F8000000F8000000F8000000F8000000F80000 181 | 00F8000000F8000000780000007C0000103C0000103C0000101E0000201E0000200F0000 182 | 200780004003C0008000E0030000380C00000FF0001C217E9F21>IIII<000FE01000381C3000E002 194 | 7003C00170078000F00F0000701E0000701E0000303C0000303C0000107C000010780000 195 | 10F8000000F8000000F8000000F8000000F8000000F8000000F8000000F8003FFEF80001 196 | F0780000F07C0000F03C0000F03C0000F01E0000F01E0000F00F0000F0078000F003C001 197 | 7000E0023000380C10000FF0001F217E9F24>III<07FFC0003E00001E00001E00001E00001E00001E00001E00001E00001E00001E 204 | 00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E00001E 205 | 00201E00F81E00F81E00F81E00F01C00403C006038001070000FC00012207F9E17>IIII<001FE000 217 | 0070380001C00E0003800700070003800F0003C01E0001E03C0000F03C0000F07C0000F8 218 | 7C0000F878000078F800007CF800007CF800007CF800007CF800007CF800007CF800007C 219 | F800007CF800007C780000787C0000F87C0000F83C0000F03E0001F01E0001E00F0003C0 220 | 070003800380070001E01E0000703800001FE0001E217E9F23>79 221 | DI<001FE0000070380001C00E00 225 | 03800700070003800F0003C01E0001E03E0001F03C0000F07C0000F87C0000F878000078 226 | F800007CF800007CF800007CF800007CF800007CF800007CF800007CF800007CF800007C 227 | 780000787C0000F87C0000F83C0000F03E0781F01E0841E00F1023C00710238003901700 228 | 01D01E0000783804001FF80400001C0400000C0C00000E1C00000FF800000FF8000007F8 229 | 000007F0000001E01E297E9F23>II<03F0400C0CC01803C03001C06000C06000C0E000C0E00040E00040E00040 234 | F00000F800007C00007F80003FF8001FFF0007FF8000FFC0001FE00003E00001E00000F0 235 | 000070800070800070800070800070C00060C000E0E000C0F80180C6030081FC0014217E 236 | 9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010 237 | 800F0010800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000 238 | 000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000 239 | 000F0000000F0000000F0000001F800003FFFC001C1F7E9E21>II 249 | 87 D89 D<080410082010201040 253 | 204020804080408040B85CFC7EFC7E7C3E381C0F0E7A9F17>92 D<1FE000303000781800 254 | 781C00300E00000E00000E00000E0000FE00078E001E0E00380E00780E00F00E10F00E10 255 | F00E10F01E10781E103867200F83C014147E9317>97 D<1C0000FC00001C00001C00001C 256 | 00001C00001C00001C00001C00001C00001C00001C00001C7C001D87001E01801E00C01C 257 | 00E01C00701C00701C00781C00781C00781C00781C00781C00781C00701C00F01C00E01E 258 | 00C01A0180198700107C0015207E9F19>I<01FC000706001C0F00380F00380600780000 259 | 700000F00000F00000F00000F00000F00000F000007000007800003800803800801C0100 260 | 07060001F80011147F9314>I<0001C0000FC00001C00001C00001C00001C00001C00001 261 | C00001C00001C00001C00001C001F1C0070DC00C03C01801C03801C07801C07001C0F001 262 | C0F001C0F001C0F001C0F001C0F001C07001C07001C03801C01803C00C03C0070DC001F1 263 | F815207F9F19>I<03F0000E1C001C0E00380700380700700700700380F00380F00380FF 264 | FF80F00000F00000F000007000007000003800803800801C010007060001F80011147F93 265 | 14>I<007C01C6030F070F0E060E000E000E000E000E000E000E00FFF00E000E000E000E 266 | 000E000E000E000E000E000E000E000E000E000E000E000E000E000E007FE01020809F0E 267 | >I<0000E003E3300E3C301C1C30380E00780F00780F00780F00780F00780F00380E001C 268 | 1C001E380033E0002000002000003000003000003FFE001FFF801FFFC03001E0600070C0 269 | 0030C00030C00030C000306000603000C01C038003FC00141F7F9417>I<1C0000FC0000 270 | 1C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C7C001C8600 271 | 1D03001E03801E03801C03801C03801C03801C03801C03801C03801C03801C03801C0380 272 | 1C03801C03801C03801C03801C0380FF8FF014207E9F19>I<38007C007C007C00380000 273 | 00000000000000000000001C00FC001C001C001C001C001C001C001C001C001C001C001C 274 | 001C001C001C001C001C001C00FF80091F7F9E0C>I<1C0000FC00001C00001C00001C00 275 | 001C00001C00001C00001C00001C00001C00001C00001C1FE01C07801C06001C04001C08 276 | 001C10001C20001C60001CE0001DF0001E70001C38001C3C001C1C001C0E001C0F001C07 277 | 001C07801C07C0FF9FF014207E9F18>107 D<1C00FC001C001C001C001C001C001C001C 278 | 001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C001C 279 | 001C001C001C001C00FF8009207F9F0C>I<1C3E03E000FCC30C30001D039038001E01E0 280 | 1C001E01E01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C 281 | 001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C001C01C01C00 282 | 1C01C01C00FF8FF8FF8021147E9326>I<1C7C00FC86001D03001E03801E03801C03801C 283 | 03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C 284 | 0380FF8FF014147E9319>I<01F800070E001C03803801C03801C07000E07000E0F000F0 285 | F000F0F000F0F000F0F000F0F000F07000E07000E03801C03801C01C0380070E0001F800 286 | 14147F9317>I<1C7C00FD87001E01801E01C01C00E01C00F01C00701C00781C00781C00 287 | 781C00781C00781C00781C00701C00F01C00E01E01C01E03801D87001C7C001C00001C00 288 | 001C00001C00001C00001C00001C00001C0000FF8000151D7E9319>I<01F040070CC00E 289 | 02C01C03C03801C07801C07001C0F001C0F001C0F001C0F001C0F001C0F001C07001C078 290 | 01C03801C01C03C00C05C00709C001F1C00001C00001C00001C00001C00001C00001C000 291 | 01C00001C0000FF8151D7F9318>I<1CF0FD181E3C1E3C1E181C001C001C001C001C001C 292 | 001C001C001C001C001C001C001C001C00FFC00E147E9312>I<0FC830386018C008C008 293 | C008E0007C003FE01FF007F8003C800E8006C006C006C004E00CD81887E00F147F9312> 294 | I<020002000200060006000E000E003E00FFF80E000E000E000E000E000E000E000E000E 295 | 000E000E000E040E040E040E040E040708030801F00E1C7F9B12>I<1C0380FC1F801C03 296 | 801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03801C03 297 | 801C03801C07800C0780061B8003E3F014147E9319>IIIII<7FFF700E600E401C40384078407000E001E001C00380 307 | 078007010E011E011C0338027006700EFFFE10147F9314>I E /Fc 308 | 36 123 df<000FF01FC000007FF8FFF00000F81FE0780001E03F80F80003E07F80F80007 309 | C07F00F80007C07F00F80007C03F00700007C01F00000007C01F00000007C01F00000007 310 | C01F03FC00FFFFFFFFFC00FFFFFFFFFC0007C01F007C0007C01F007C0007C01F007C0007 311 | C01F007C0007C01F007C0007C01F007C0007C01F007C0007C01F007C0007C01F007C0007 312 | C01F007C0007C01F007C0007C01F007C0007C01F007C0007C01F007C0007C01F007C0007 313 | C01F007C003FF8FFE3FF803FF8FFE3FF802920809F2C>14 D45 D<387CFEFEFE7C38000000000000387CFEFEFE7C3807147C930F>58 315 | D<0000E000000000E000000001F000000001F000000001F000000003F800000003F80000 316 | 0006FC00000006FC0000000EFE0000000C7E0000000C7E000000183F000000183F000000 317 | 303F800000301F800000701FC00000600FC00000600FC00000C007E00000FFFFE00001FF 318 | FFF000018003F000038003F800030001F800030001F800060000FC00060000FC000E0000 319 | FE00FFE00FFFE0FFE00FFFE0231F7E9E28>65 D<0007FC02003FFF0E00FE03DE03F000FE 320 | 07E0003E0FC0001E1F80001E3F00000E3F00000E7F0000067E0000067E000006FE000000 321 | FE000000FE000000FE000000FE000000FE000000FE0000007E0000007E0000067F000006 322 | 3F0000063F00000C1F80000C0FC0001807E0003803F0007000FE01C0003FFF800007FC00 323 | 1F1F7D9E26>67 D69 327 | DI<0007FC0200003FFF0E0000FE 331 | 03DE0003F000FE0007E0003E000FC0001E001F80001E003F00000E003F00000E007F0000 332 | 06007E000006007E00000600FE00000000FE00000000FE00000000FE00000000FE000000 333 | 00FE001FFFE0FE001FFFE07E00007E007E00007E007F00007E003F00007E003F00007E00 334 | 1F80007E000FC0007E0007E0007E0003F000FE0000FE01FE00003FFF8E000007FC060023 335 | 1F7D9E29>III76 D<001FF80000FFFF0001F81F8007E007E00FC003F01F8001F81F0000 346 | F83F0000FC7F0000FE7E00007E7E00007EFE00007FFE00007FFE00007FFE00007FFE0000 347 | 7FFE00007FFE00007FFE00007FFE00007F7E00007E7F0000FE7F0000FE3F0000FC3F8001 348 | FC1F8001F80FC003F007E007E001F81F8000FFFF00001FF800201F7D9E27>79 349 | D<001FF80000FFFF0001F81F8007E007E00FC003F01F8001F81F8001F83F0000FC7F0000 350 | FE7F0000FE7E00007EFE00007FFE00007FFE00007FFE00007FFE00007FFE00007FFE0000 351 | 7FFE00007FFE00007F7E00007E7E00007E7F0000FE3F0000FC3F87C1FC1F8FF1F80FDC3B 352 | F007F83FE001FC1F8000FFFF00001FFE0300000F0300000F8700000FFF00000FFF000007 353 | FE000007FE000003FC000003FC000000F020287D9E27>81 DI<03FC080FFF381E03F83800F8700078700038F00038F00018F00018F800 359 | 00FC00007FC0007FFE003FFF801FFFC00FFFE007FFF000FFF80007F80000FC00007C0000 360 | 3CC0003CC0003CC0003CE00038E00078F80070FE01E0EFFFC081FF00161F7D9E1D>I<7F 361 | FFFFFC7FFFFFFC7C07E07C7007E01C6007E00C6007E00CE007E00EC007E006C007E006C0 362 | 07E006C007E0060007E0000007E0000007E0000007E0000007E0000007E0000007E00000 363 | 07E0000007E0000007E0000007E0000007E0000007E0000007E0000007E0000007E00000 364 | 07E00003FFFFC003FFFFC01F1E7E9D24>I<07FC001FFF803F07C03F03E03F01F03F01F0 365 | 0C01F00001F0003FF007FDF01F81F03E01F07C01F0F801F0F801F0F801F0FC02F07E0CF0 366 | 3FF8FE0FE03E17147F9319>97 DI<01FE0007FF801F0FC03E0FC03E0FC07C0FC07C0300FC0000FC0000 370 | FC0000FC0000FC0000FC00007C00007E00003E00603F00C01F81C007FF0001FC0013147E 371 | 9317>I<0007F80007F80000F80000F80000F80000F80000F80000F80000F80000F80000 372 | F80000F801F8F807FEF81F83F83E01F87E00F87C00F87C00F8FC00F8FC00F8FC00F8FC00 373 | F8FC00F8FC00F87C00F87C00F87E00F83E01F81F07F80FFEFF03F8FF18207E9F1D>I<01 374 | FE0007FF801F83E03F01F07E00F07E00F8FC00F8FC00F8FFFFF8FFFFF8FC0000FC0000FC 375 | 00007C00007E00003E00183F00380F807007FFE000FF8015147F9318>I104 D<1C007F007F007F007F 379 | 007F001C00000000000000000000000000FF00FF001F001F001F001F001F001F001F001F 380 | 001F001F001F001F001F001F001F001F00FFE0FFE00B217EA00E>I107 DIII<01FF0007FFC01F83F03E00F83E00F87C007C 391 | 7C007CFC007EFC007EFC007EFC007EFC007EFC007E7C007C7C007C3E00F83E00F81F83F0 392 | 07FFC001FF0017147F931A>II114 397 | D<0FE63FFE701E600EE006E006F800FFC07FF83FFC1FFE03FE001FC007C007E007F006F8 398 | 1EFFFCC7F010147E9315>I<0300030003000300070007000F000F003F00FFFCFFFC1F00 399 | 1F001F001F001F001F001F001F001F001F001F061F061F061F061F060F8C07F803F00F1D 400 | 7F9C14>II< 402 | FFC7FE1FE0FFC7FE1FE01F00F003001F00F803000F80F806000F80F806000FC1BC0E0007 403 | C1BC0C0007C3BE0C0003E31E180003E31E180003F60F380001F60F300001FE0FB00000FC 404 | 07E00000FC07E00000F803E000007803C000007803C000003001800023147F9326>119 405 | D121 D<3FFFE03FFFE03C0FC0381FC0701F80603F00 409 | 607E0060FE0000FC0001F80003F00007E0600FE0600FC0601F80E03F00C07F01C07E03C0 410 | FFFFC0FFFFC013147F9317>I E /Fd 13 90 df45 D<003F800001FFF00007E0FC000FC07E001F803F001F001F003F00 412 | 1F803E000F807E000FC07E000FC07E000FC07E000FC0FE000FE0FE000FE0FE000FE0FE00 413 | 0FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE000FE0FE00 414 | 0FE0FE000FE0FE000FE07E000FC07E000FC07E000FC07E000FC03F001F803F001F801F00 415 | 1F001F803F000FC07E0007E0FC0001FFF000003F80001B277DA622>48 416 | D<00FF800007FFF0000FFFFC001E03FE003800FF807C003F80FE003FC0FF001FC0FF001F 417 | E0FF000FE0FF000FE07E000FE03C001FE000001FE000001FC000001FC000003F8000003F 418 | 0000007E000000FC000000F8000001F0000003E00000078000000F0000001E0000003C00 419 | E0007000E000E000E001C001C0038001C0060001C00FFFFFC01FFFFFC03FFFFFC07FFFFF 420 | C0FFFFFF80FFFFFF80FFFFFF801B277DA622>50 D<00000F0000000F0000001F0000003F 421 | 0000007F000000FF000001FF000001FF000003BF0000073F00000E3F00001C3F00003C3F 422 | 0000383F0000703F0000E03F0001C03F0003803F0007803F0007003F000E003F001C003F 423 | 0038003F0070003F00F0003F00FFFFFFF8FFFFFFF8FFFFFFF800007F0000007F0000007F 424 | 0000007F0000007F0000007F0000007F0000007F00001FFFF8001FFFF8001FFFF81D277E 425 | A622>52 D<0007F800003FFE0000FFFF0001FC078003F00FC007C01FC00F801FC01F801F 426 | C01F001FC03F000F803F0000007E0000007E0000007E000000FE020000FE1FF000FE3FFC 427 | 00FE603E00FE801F00FF801F80FF000FC0FF000FC0FE000FE0FE000FE0FE000FE0FE000F 428 | E07E000FE07E000FE07E000FE07E000FE03E000FE03F000FC01F000FC01F001F800F801F 429 | 0007E07E0003FFFC0001FFF800003FC0001B277DA622>54 D<0000078000000000078000 430 | 0000000FC0000000000FC0000000000FC0000000001FE0000000001FE0000000003FF000 431 | 0000003FF0000000003FF00000000077F80000000077F800000000F7FC00000000E3FC00 432 | 000000E3FC00000001C1FE00000001C1FE00000003C1FF0000000380FF0000000380FF00 433 | 000007007F80000007007F8000000F007FC000000E003FC000000E003FC000001C001FE0 434 | 00001C001FE000003FFFFFF000003FFFFFF000003FFFFFF00000700007F80000700007F8 435 | 0000F00007FC0000E00003FC0001E00003FE0001C00001FE0001C00001FE0003C00001FF 436 | 00FFFE003FFFFCFFFE003FFFFCFFFE003FFFFC2E297EA833>65 D<00007FE0030007FFFC 437 | 07001FFFFF0F007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F 438 | 1FC000001F1FC000000F3F8000000F3F800000077F800000077F800000077F00000000FF 439 | 00000000FF00000000FF00000000FF00000000FF00000000FF00000000FF00000000FF00 440 | 000000FF000000007F000000007F800000007F800000073F800000073F800000071FC000 441 | 00071FC000000E0FE000000E07F000001C03F800003C01FC00007800FF0001F0007FF007 442 | C0001FFFFF800007FFFE0000007FF00028297CA831>67 D73 D76 D<0000FFC00000000FFFFC0000003F807F000000FE001FC00001F80007 453 | E00003F00003F00007E00001F8000FE00001FC001FC00000FE001FC00000FE003F800000 454 | 7F003F8000007F007F8000007F807F0000003F807F0000003F807F0000003F80FF000000 455 | 3FC0FF0000003FC0FF0000003FC0FF0000003FC0FF0000003FC0FF0000003FC0FF000000 456 | 3FC0FF0000003FC0FF0000003FC0FF0000003FC07F0000003F807F8000007F807F800000 457 | 7F803F8000007F003F8000007F001FC00000FE001FC00000FE000FE00001FC0007F00003 458 | F80003F80007F00001FC000FE00000FE001FC000003FC0FF0000000FFFFC00000000FFC0 459 | 00002A297CA833>79 DI<00FF806003FFF0E00FFFF8E01F80FDE03F001FE03E0007E07C0003E07C00 466 | 03E0FC0001E0FC0001E0FC0000E0FE0000E0FE0000E0FF000000FFC000007FFC00007FFF 467 | E0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE000007FE00000 468 | 1FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003E0F800 469 | 07E0FC0007C0FF000F80FFE03F80E3FFFE00E1FFFC00C01FF0001C297CA825>83 470 | D89 D E end 478 | %%EndProlog 479 | %%BeginSetup 480 | %%Feature: *Resolution 300dpi 481 | TeXDict begin 482 | %%PaperSize: Letter 483 | 484 | %%EndSetup 485 | %%Page: 1 1 486 | 1 0 bop 616 199 a Fd(26L-04)22 b(CLASS)h(POLICY)174 338 487 | y Fc(Instructor:)49 b Fb(Laura)15 b(T)l(aalman)403 b 488 | Fc(O\016ce:)49 b Fb(020)14 b(Math/Ph)o(ysics)174 395 489 | y Fc(T)l(elephone:)50 b Fb(660-2829)13 b(\(W\),)h(220-1359)g(\(H\))129 490 | b Fc(E-mail:)51 b Fb(taal@math.duk)o(e.edu)75 568 y(General)13 491 | b(p)q(olicies)j(for)c(26L)h(are)f(found)h(in)h(y)o(our)e(Coursepac)o(k) 492 | h(on)g(pages)g(5-14.)18 b(P)o(olicies)c(sp)q(eci\014c)h(to)d(m)o(y)75 493 | 624 y(section)j(are)f(listed)h(b)q(elo)o(w,)g(and)f(sup)q(ercede)i(an)o 494 | (y)e(p)q(olicies)j(in)e(the)f(coursepac)o(k.)20 b(Y)l(ou)14 495 | b(are)g(exp)q(ected)i(to)75 681 y(understand)c(and)h(agree)e(to)g(all)i 496 | (of)f(these)g(p)q(olicies.)21 b(I)12 b(will)i(b)q(e)e(unimpressed)i(if) 497 | e(I)g(ha)o(v)o(e)g(to)f(answ)o(er)h(lots)f(of)75 737 498 | y(questions)j(throughout)f(the)h(semester)f(whose)h(answ)o(ers)f(can)g 499 | (b)q(e)i(found)f(here)g(or)f(in)h(the)g(Coursepac)o(k.)75 500 | 844 y Fc(Grades)f Fb(Y)l(our)h(grade)g(for)f(this)h(course)g(will)i(b)q 501 | (e)e(determined)h(almost)f(en)o(tirely)h(b)o(y)e(y)o(our)h(p)q 502 | (erformance)75 900 y(on)20 b(quizzes,)i(tests,)f(and)f(the)g(\014nal)h 503 | (exam.)34 b(I)20 b(exp)q(ect)h(the)f(distribution)i(of)e(p)q(oin)o(ts)g 504 | (\(and)g(th)o(us)g(the)75 956 y(corresp)q(onding)c(p)q(ercen)o(tages\)) 505 | f(to)g(b)q(e)h(as)e(follo)o(ws:)p 304 1069 1342 2 v 303 506 | 1137 2 68 v 353 1116 a(W)l(eekly)i(Quizzes)p 712 1137 507 | V 99 w(10)f(@)g(25)g(pts)p 1041 1137 V 97 w(250)f(total)g(pts)p 508 | 1391 1137 V 97 w(31.25)g(\045)p 1645 1137 V 303 1205 509 | V 353 1184 a(Lab)i(Rep)q(orts)p 712 1205 V 171 w(2)f(@)h(25)e(pts)p 510 | 1041 1205 V 131 w(50)h(total)f(pts)p 1391 1205 V 120 511 | w(6.25)g(\045)p 1645 1205 V 303 1272 V 353 1252 a(T)l(ests)p 512 | 712 1272 V 305 w(3)h(@)g(100)g(pts)p 1041 1272 V 97 w(300)f(total)g 513 | (pts)p 1391 1272 V 97 w(37.50)g(\045)p 1645 1272 V 303 514 | 1340 V 353 1320 a(Final)i(Exam)p 712 1340 V 174 w(1)f(@)g(200)g(pts)p 515 | 1041 1340 V 97 w(200)f(total)g(pts)p 1391 1340 V 97 w(25.00)g(\045)p 516 | 1645 1340 V 304 1342 1342 2 v 75 1486 a(W)l(eekly)f(quiz)g(scores)f 517 | (can)g(b)q(e)h(mo)q(di\014ed)h(b)o(y)e(y)o(our)g(score)g(on)g 518 | (\\attendance)g(quizzes")h(and)f(y)o(our)g(comple-)75 519 | 1543 y(tion)f(of)e(\\gatew)o(a)o(y)g(homew)o(orks")g(\(where)h 520 | (applicable\).)20 b(T)l(est)11 b(scores)f(can)g(b)q(e)h(increased)h(b)o 521 | (y)e(completion)75 1599 y(of)k(c)o(heat)g(sheets.)20 522 | b(The)15 b(\014nal)g(exam)f(ma)o(y)g(end)h(up)g(coun)o(ting)f(as)g 523 | (more)g(than)h(25)f(\045)g(of)g(y)o(our)g(grade;)g(see)75 524 | 1656 y(page)h(11)g(in)h(y)o(our)e(coursepac)o(k)i(for)e(more)h 525 | (information.)75 1762 y Fc(A)o(ttendance)20 b(and)g(Absences:)j 526 | Fb(It)17 b(is)h(imp)q(erativ)o(e)g(that)f(y)o(ou)g(come)g(to)f(class)i 527 | (eac)o(h)f(da)o(y)g(and)h(tak)o(e)75 1819 y(careful)11 528 | b(notes.)18 b(I)10 b(will)i(tak)o(e)e(random)g(\\attendance)g(quizzes") 529 | h(throughout)e(the)i(semester)f(to)f(k)o(eep)i(trac)o(k)75 530 | 1875 y(of)i(who)g(is)h(attending)f(class.)20 b(Eac)o(h)13 531 | b(of)g(these)g(quizzes)i(will)g(b)q(e)f(w)o(orth)e(t)o(w)o(o)g(extra)g 532 | (p)q(oin)o(ts)i(to)o(w)o(ards)e(that)75 1931 y(w)o(eek's)h(homew)o 533 | (ork/lab)f(quiz)i(\(not)e(to)h(exceed)h(25)e(total)h(p)q(oin)o(ts\);)g 534 | (these)g(quizzes)i(cannot)e(b)q(e)g(made)g(up)75 1988 535 | y(for)i(an)o(y)h(reason.)21 b(If)16 b(y)o(ou)f(do)h(miss)g(class)g(it)g 536 | (is)g(y)o(our)f(resp)q(onsibilit)o(y)j(to)e(\014nd)g(out)f(\(from)g(a)g 537 | (classmate\))75 2044 y(what)j(y)o(ou)h(missed,)h(includin)q(g)h(class)f 538 | (notes,)f(announcemen)o(ts,)h(and)f(w)o(orksheets.)31 539 | b(Absences)20 b(from)75 2101 y(tests)15 b(will)i(b)q(e)g(excused)f 540 | (only)g(for)f(reasons)g(suc)o(h)h(as)g(serious)g(illness)h(or)e 541 | (o\016cial)i(univ)o(ersit)o(y)f(activities.)75 2157 y(In)g(some)g 542 | (cases)g(the)f(studen)o(t)h(can)g(obtain)g(an)g(excuse)g(from)f 543 | (his/her)i(Dean.)k(A)16 b(studen)o(t)g(who)g(misses)75 544 | 2214 y(a)f(test)g(b)q(ecause)h(of)f(illness)j(and)e(cannot)f(obtain)g 545 | (a)g(Dean's)g(excuse)h(should)h(pic)o(k)f(up)g(a)f(departmen)o(tal)75 546 | 2270 y(excuse)d(form)e(from)g(the)h(Mathematics)f(Departmen)o(t)g 547 | (O\016ce,)i(121)e(Ph)o(ysics)h(Bldg.,)h(\014ll)h(it)e(out,)g(and)g(tak) 548 | o(e)75 2327 y(it)i(to)f(Lewis)i(Blak)o(e,)f(the)g(Sup)q(ervisor)g(of)g 549 | (First-Y)l(ear)f(Instruction,)i(118)e(Ph)o(ysics)h(Bldg.)20 550 | b(If)12 b(the)h(absence)75 2383 y(is)j(excused,)g(the)g(studen)o(t's)f 551 | (grade)g(on)h(the)f(missed)i(test)e(will)i(b)q(e)f(determined)h(either) 552 | f(b)o(y)g(assigning)g(a)75 2440 y(score)g(according)h(to)e(his/her)i(p) 553 | q(erformance)f(on)g(the)g(\014nal)h(exam)f(relativ)o(e)h(to)e(other)h 554 | (studen)o(ts)g(in)h(the)75 2496 y(class)f(or)e(b)o(y)h(a)g(mak)o(e-up)h 555 | (test,)e(at)g(m)o(y)h(discretion.)75 2602 y Fc(Homew)o(ork:)k 556 | Fb(Homew)o(ork)c(\(b)q(oth)g(the)h(reading)h(and)f(the)g(exercises\))g 557 | (should)h(b)q(e)f(completed)h(b)o(y)f(the)75 2659 y(next)c(class)h 558 | (after)f(it)g(is)h(assigned.)19 b(Homew)o(ork)12 b(will)i(not)d(b)q(e)i 559 | (collected,)i(although)d(y)o(our)g(understanding)75 2715 560 | y(of)j(it)h(will)h(b)q(e)g(tested)e(in)i(eac)o(h)f(w)o(eekly)g(quiz)g 561 | (and)g(eac)o(h)g(test.)21 b(It)15 b(is)h(y)o(our)g(resp)q(onsibilit)o 562 | (y)i(to)d(seek)h(help)75 2772 y(on)i(all)g(problems)g(that)f(y)o(ou)h 563 | (cannot)f(do.)27 b(Help)19 b(is)f(a)o(v)m(ailable)i(after)c(class,)j 564 | (in)f(the)g(help)h(ro)q(om)e(or)g(b)o(y)75 2828 y(app)q(oin)o(tmen)o(t) 565 | e(with)h(me.)k(I)15 b(will)i(not)e(discuss)h(homew)o(ork)f(problems)g 566 | (in)i(class.)p eop 567 | %%Page: 2 2 568 | 2 1 bop 75 199 a Fc(Quizzes:)29 b Fb(There)20 b(will)h(b)q(e)f(a)f(25)g 569 | (p)q(oin)o(t,)i(25)e(min)o(ute)h(quiz)g(at)f(the)g(b)q(eginning)j(of)d 570 | (eac)o(h)h(lab)g(p)q(erio)q(d)75 256 y(\(except)j(for)e(the)i(\014rst)f 571 | (w)o(eek,)i(and)f(the)f(w)o(eeks)g(where)h(tests)f(o)q(ccur\).)42 572 | b(The)22 b(quiz)i(will)g(co)o(v)o(er)e(the)75 312 y(previous)17 573 | b(w)o(eek's)f(lab)h(\(if)f(there)h(w)o(as)e(one\),)h(and)h(the)f(homew) 574 | o(ork)g(from)g(the)g(last)g(w)o(eek)h(\(sp)q(eci\014cally)l(,)75 575 | 369 y(the)j(W)l(ednesda)o(y)g(and)f(F)l(rida)o(y)h(of)f(the)h(previous) 576 | g(w)o(eek,)g(and)g(the)g(Monda)o(y)f(of)g(the)g(curren)o(t)h(w)o 577 | (eek\).)75 425 y(Keep)c(in)g(mind)g(that)f(four)g(of)f(these)i(homew)o 578 | (ork/lab)e(quizzes)j(are)e(w)o(orth)f(as)h(m)o(uc)o(h)g(as)g(a)g(test!) 579 | 75 531 y Fc(Labs:)j Fb(There)12 b(will)i(b)q(e)e(a)f(lab)i(eac)o(h)e 580 | (Th)o(ursda)o(y)l(,)h(usually)h(b)q(eginning)h(with)e(the)g(homew)o 581 | (ork/lab)f(quiz)i(for)75 588 y(that)g(w)o(eek.)20 b(If)14 582 | b(y)o(ou)g(are)g(late)g(to)g(lab)g(y)o(ou)g(will)i(ha)o(v)o(e)d(less)i 583 | (time)g(to)e(tak)o(e)h(this)g(quiz.)21 b(Y)l(ou)14 b(are)g(exp)q(ected) 584 | 75 644 y(to)d(read)i(through)e(the)i(lab)f(in)h(the)f(Coursepac)o(k)g 585 | (or)g(b)q(o)q(ok)g(b)q(efore)h(coming)f(to)g(lab.)19 586 | b(There)12 b(is)h(no)f(sp)q(eci\014c)75 701 y(calculator)k(required)g 587 | (for)f(this)h(class)g(but)f(y)o(ou)g(should)h(bring)g(some)f(form)g(of) 588 | g(graphing)h(calculator)g(to)75 757 y(class)k(and)g(lab)g(\(see)g 589 | Fa(http://www.math.duke.ed)o(u/first_)o(year/ca)o(lculato)o(r.html)c 590 | Fb(and)k(page)75 814 y(12)15 b(of)g(y)o(our)g(coursepac)o(k\).)21 591 | b(During)16 b(the)g(lab)g(y)o(ou)g(will)h(w)o(ork)e(in)h(pairs)g(\(if)g 592 | (there)g(are)f(an)h(o)q(dd)g(n)o(um)o(b)q(er)75 870 y(of)e(studen)o(ts) 593 | g(there)g(will)i(b)q(e)f(one)p 567 877 69 2 v 14 w(group)f(of)g 594 | (three\);)g(please)h(c)o(ho)q(ose)g(a)f(p)q(ermanen)o(t)g(lab)h 595 | (partner)f(b)o(y)g(the)75 927 y(second)h(lab.)20 b(If)15 596 | b(y)o(ou)f(do)h(not)f(complete)h(the)g(lab)g(during)h(the)e(lab)h(p)q 597 | (erio)q(d)h(\(as)e(is)h(often)g(the)f(case\),)g(y)o(ou)75 598 | 983 y(and)h(y)o(our)g(lab)g(partner)g(are)g(exp)q(ected)h(to)e(\014nd)i 599 | (time)f(to)g(w)o(ork)f(together)g(out)g(of)h(class)g(and)h(\014nish)g 600 | (the)75 1039 y(lab.)29 b(The)18 b(labs)g(will)i(not)d(b)q(e)i 601 | (collected)g(\(although)f(there)g(will)i(b)q(e)e(t)o(w)o(o)f(lab)h(rep) 602 | q(orts\).)28 b(Y)l(ou)18 b(will)h(b)q(e)75 1096 y(tested)14 603 | b(on)g(y)o(our)f(understanding)i(of)f(the)g(lab)g(material)h(on)e(the)h 604 | (quizzes,)i(tests,)d(and)h(the)g(\014nal)h(exam.)75 1202 605 | y Fc(T)l(ests)j(and)h(Cheat)g(Sheets:)i Fb(There)c(will)g(b)q(e)g 606 | (three)f(tests)g(in)h(this)f(course,)g(eac)o(h)g(taking)g(an)h(en)o 607 | (tire)75 1259 y(lab)f(p)q(erio)q(d.)23 b(Please)16 b(see)g(\\Absences") 608 | g(ab)q(o)o(v)o(e)g(for)f(related)h(information.)22 b(I)16 609 | b(do)f(not)h(allo)o(w)g(the)f(use)h(of)75 1315 y(\\c)o(heat)d(sheets")h 610 | (during)g(the)g(exams.)19 b(Ho)o(w)o(ev)o(er,)12 b(since)j(some)e 611 | (other)g(sections)i(do)e(allo)o(w)h(c)o(heat)f(sheets,)75 612 | 1372 y(and)g(y)o(ou)g(will)i(b)q(e)f(allo)o(w)o(ed)f(to)g(use)g(a)g(c)o 613 | (heat)g(sheet)g(during)h(the)g(\014nal)g(exam,)e(I)i(encourage)f(y)o 614 | (ou)g(to)f(mak)o(e)75 1428 y(a)17 b(one-page,)g(t)o(w)o(o-sided)g(\\c)o 615 | (heat)g(sheet")f(for)h(eac)o(h)g(test.)25 b(I)17 b(will)i(collect)f 616 | (these)f(c)o(heat)g(sheets)g(\(b)q(efore)p 1754 1435 617 | 122 2 v 75 1484 a(eac)o(h)e(test,)g(of)g(course\).)20 618 | b(Y)l(ou)15 b(can)h(earn)f(up)h(to)f(three)g(extra)g(p)q(oin)o(ts)h(on) 619 | f(the)g(test)g(\(not)g(to)f(exceed)j(100)75 1541 y(total)h(p)q(oin)o 620 | (ts\))g(for)g(handing)h(in)h(a)e(complete)h(c)o(heat)f(sheet.)30 621 | b(It)18 b(should)h(b)q(e)h(m)o(uc)o(h)e(easier)h(for)f(y)o(ou)g(to)75 622 | 1597 y(mak)o(e)d(y)o(our)f(\014nal)i(exam)f(c)o(heat)g(sheet)h(if)f(y)o 623 | (ou)g(ha)o(v)o(e)g(already)g(made)h(one)f(for)g(eac)o(h)g(test.)75 624 | 1704 y Fc(The)i(Final:)j Fb(The)15 b(\014nal)g(exam)e(for)h(this)h 625 | (course)f(is)g(a)g(\\blo)q(c)o(k")h(\014nal,)f(meaning)h(all)g 626 | (sections)g(will)h(tak)o(e)75 1760 y(the)k(same)f(exam;)i(the)f 627 | (\014nal)g(will)h(b)q(e)g(giv)o(en)f(on)f(T)l(uesda)o(y)l(,)i(Ma)o(y)d 628 | (4,)i(1999)f(at)g(7)g(pm)h(-)f(10)g(pm.)33 b(See)75 1817 629 | y(h)o(ttp://registrar.duk)o(e.edu/registrar/exams99)o(.h)o(tm)10 630 | b(and)k(page)g(11)g(in)g(y)o(our)g(Coursepac)o(k)f(for)g(more)75 631 | 1873 y(information.)75 1979 y Fc(The)j(Gatew)o(a)o(y:)i 632 | Fb(Y)l(ou)c(will)h(ha)o(v)o(e)d(to)h(pass)g(a)g(di\013eren)o(tiation)h 633 | (gatew)o(a)o(y)e(to)h(get)f(credit)i(for)f(this)h(course)75 634 | 2036 y(\(see)19 b(page)g(12)f(in)i(y)o(our)e(coursepac)o(k\).)31 635 | b(An)o(y)o(one)19 b(who)f(do)q(es)i(not)e(pass)h(the)g(gatew)o(a)o(y)e 636 | (the)i(\014rst)g(time)75 2092 y(will)i(ha)o(v)o(e)e(to)g(hand)h(in)g(a) 637 | f(\\gatew)o(a)o(y)f(homew)o(ork")g(in)i(class)g(eac)o(h)f(F)l(rida)o(y) 638 | h(un)o(til)g(they)g(ha)o(v)o(e)f(passed)75 2149 y(the)14 639 | b(gatew)o(a)o(y)l(.)k(Unsatisfactory)13 b(p)q(erformance)h(on)g(this)h 640 | (homew)o(ork)e(will)j(result)e(in)h(a)f(deduction)h(of)e(up)75 641 | 2205 y(to)i(\014v)o(e)h(p)q(oin)o(ts)g(\(not)f(to)g(b)q(e)i(lo)o(w)o 642 | (er)e(than)h(0)f(total)g(p)q(oin)o(ts\))h(from)f(y)o(our)g(previous)i 643 | (homew)o(ork/lab)e(quiz)75 2262 y(score.)75 2368 y Fc(Help)k(Ro)q(om:)k 644 | Fb(I)16 b(strongly)g(suggest)g(that)g(y)o(ou)g(visit)h(the)f(help)i(ro) 645 | q(om)e(often,)g(esp)q(ecially)j(during)e(the)75 2424 646 | y(hours)g(that)g(I)h(will)h(b)q(e)f(w)o(orking)f(there)h(\(to)e(b)q(e)i 647 | (announced\),)g(and)g(while)h(other)e(26L)g(instructors)g(or)75 648 | 2481 y(lab)g(T)l(As)f(are)h(there.)23 b(The)17 b(help)h(ro)q(om)e(is)g 649 | (in)i(08)e(W)l(est)g(Duk)o(e)g(\(in)h(the)g(basemen)o(t\))f(and)g(is)h 650 | (op)q(en)g(1:00)75 2537 y(pm)g(-)h(10:00)d(pm)j(Monda)o(y)e(-)i(Th)o 651 | (ursda)o(y)f(and)g(6:00)f(pm)h(-)h(10:00)e(pm)h(Sunda)o(y)l(.)27 652 | b(The)17 b(help)i(ro)q(om)d(will)75 2594 y(b)q(egin)f(on)f(Sunda)o(y)l 653 | (,)g(Jan)o(uary)f(17,)g(1999,)g(and)h(op)q(erate)f(through)h(Sunda)o(y) 654 | l(,)g(Ma)o(y)f(2,)g(except)h(for)f(Martin)75 2650 y(Luther)23 655 | b(King's)f(birthda)o(y)h(on)f(Monda)o(y)l(,)h(Jan)o(uary)f(18,)h(and)f 656 | (from)g(Sunda)o(y)l(,)i(Marc)o(h)d(14,)i(through)75 2707 657 | y(Sunda)o(y)l(,)17 b(Marc)o(h)f(21,)g(for)h(spring)g(break.)24 658 | b(The)17 b(help)h(ro)q(om)e(is)h(discussed)i(brie\015y)e(on)g(page)f 659 | (12)h(of)f(the)75 2763 y(Coursepac)o(k.)28 b(F)l(ollo)o(w)18 660 | b(the)g(link)h(on)f Fa(http://www.math.duke.edu/)o(first_y)o(ear/help)o 661 | (.html)d Fb(for)75 2819 y(more)g(information.)p eop 662 | %%Trailer 663 | end 664 | userdict /end-hook known{end-hook}if 665 | %%EOF 666 | --------------------------------------------------------------------------------