Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/platform/java/jni/documentwriter.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2025 Artifex Software, Inc. | |
| 2 // | |
| 3 // This file is part of MuPDF. | |
| 4 // | |
| 5 // MuPDF is free software: you can redistribute it and/or modify it under the | |
| 6 // terms of the GNU Affero General Public License as published by the Free | |
| 7 // Software Foundation, either version 3 of the License, or (at your option) | |
| 8 // any later version. | |
| 9 // | |
| 10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| 12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
| 13 // details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU Affero General Public License | |
| 16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> | |
| 17 // | |
| 18 // Alternative licensing terms are available from the licensor. | |
| 19 // For commercial licensing, see <https://www.artifex.com/> or contact | |
| 20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 21 // CA 94129, USA, for further information. | |
| 22 | |
| 23 /* DocumentWriter interface */ | |
| 24 | |
| 25 JNIEXPORT void JNICALL | |
| 26 FUN(DocumentWriter_finalize)(JNIEnv *env, jobject self) | |
| 27 { | |
| 28 fz_context *ctx = get_context(env); | |
| 29 fz_document_writer *wri = from_DocumentWriter_safe(env, self); | |
| 30 jobject ref; | |
| 31 if (!ctx || !wri) return; | |
| 32 ref = (jobject)(*env)->GetLongField(env, self, fid_DocumentWriter_ocrlistener); | |
| 33 if (ref) | |
| 34 { | |
| 35 (*env)->DeleteGlobalRef(env, ref); | |
| 36 (*env)->SetLongField(env, self, fid_DocumentWriter_ocrlistener, 0); | |
| 37 } | |
| 38 (*env)->SetLongField(env, self, fid_DocumentWriter_pointer, 0); | |
| 39 fz_drop_document_writer(ctx, wri); | |
| 40 } | |
| 41 | |
| 42 JNIEXPORT jlong JNICALL | |
| 43 FUN(DocumentWriter_newNativeDocumentWriter)(JNIEnv *env, jclass cls, jstring jfilename, jstring jformat, jstring joptions) | |
| 44 { | |
| 45 fz_context *ctx = get_context(env); | |
| 46 fz_document_writer *wri = NULL; | |
| 47 const char *filename = NULL; | |
| 48 const char *format = NULL; | |
| 49 const char *options = NULL; | |
| 50 | |
| 51 if (!ctx) return 0; | |
| 52 if (!jfilename) jni_throw_arg(env, "filename must not be null"); | |
| 53 | |
| 54 filename = (*env)->GetStringUTFChars(env, jfilename, NULL); | |
| 55 if (!filename) return 0; | |
| 56 | |
| 57 if (jformat) | |
| 58 { | |
| 59 format = (*env)->GetStringUTFChars(env, jformat, NULL); | |
| 60 if (!format) | |
| 61 { | |
| 62 (*env)->ReleaseStringUTFChars(env, jfilename, filename); | |
| 63 return 0; | |
| 64 } | |
| 65 } | |
| 66 if (joptions) | |
| 67 { | |
| 68 options = (*env)->GetStringUTFChars(env, joptions, NULL); | |
| 69 if (!options) | |
| 70 { | |
| 71 if (format) | |
| 72 (*env)->ReleaseStringUTFChars(env, jformat, format); | |
| 73 (*env)->ReleaseStringUTFChars(env, jfilename, filename); | |
| 74 return 0; | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 fz_try(ctx) | |
| 79 wri = fz_new_document_writer(ctx, filename, format, options); | |
| 80 fz_always(ctx) | |
| 81 { | |
| 82 if (options) | |
| 83 (*env)->ReleaseStringUTFChars(env, joptions, options); | |
| 84 if (format) | |
| 85 (*env)->ReleaseStringUTFChars(env, jformat, format); | |
| 86 (*env)->ReleaseStringUTFChars(env, jfilename, filename); | |
| 87 } | |
| 88 fz_catch(ctx) | |
| 89 jni_rethrow(env, ctx); | |
| 90 | |
| 91 return jlong_cast(wri); | |
| 92 } | |
| 93 | |
| 94 JNIEXPORT jlong JNICALL | |
| 95 FUN(DocumentWriter_newNativeDocumentWriterWithSeekableOutputStream)(JNIEnv *env, jclass cls, jobject jstream, jstring jformat, jstring joptions) | |
| 96 { | |
| 97 fz_context *ctx = get_context(env); | |
| 98 fz_document_writer *wri = NULL; | |
| 99 SeekableStreamState *state = NULL; | |
| 100 jobject stream = NULL; | |
| 101 const char *format = NULL; | |
| 102 const char *options = NULL; | |
| 103 jbyteArray array = NULL; | |
| 104 fz_output *out; | |
| 105 | |
| 106 if (!ctx) return 0; | |
| 107 if (!jstream) jni_throw_arg(env, "output stream must not be null"); | |
| 108 | |
| 109 stream = (*env)->NewGlobalRef(env, jstream); | |
| 110 if (!stream) | |
| 111 return 0; | |
| 112 | |
| 113 array = (*env)->NewByteArray(env, sizeof state->buffer); | |
| 114 if (array) | |
| 115 array = (*env)->NewGlobalRef(env, array); | |
| 116 if (!array) | |
| 117 { | |
| 118 (*env)->DeleteGlobalRef(env, stream); | |
| 119 return 0; | |
| 120 } | |
| 121 | |
| 122 if (jformat) | |
| 123 { | |
| 124 format = (*env)->GetStringUTFChars(env, jformat, NULL); | |
| 125 if (!format) | |
| 126 return 0; | |
| 127 } | |
| 128 if (joptions) | |
| 129 { | |
| 130 options = (*env)->GetStringUTFChars(env, joptions, NULL); | |
| 131 if (!options) | |
| 132 { | |
| 133 if (format) | |
| 134 (*env)->ReleaseStringUTFChars(env, jformat, format); | |
| 135 return 0; | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 fz_var(state); | |
| 140 fz_var(out); | |
| 141 fz_var(stream); | |
| 142 fz_var(array); | |
| 143 | |
| 144 fz_try(ctx) | |
| 145 { | |
| 146 fz_output *out_temp; | |
| 147 state = Memento_label(fz_malloc(ctx, sizeof(SeekableStreamState)), "SeekableStreamState_newNativeDocumentWriterWithSeekableOutputStream"); | |
| 148 state->stream = stream; | |
| 149 state->array = array; | |
| 150 | |
| 151 out = fz_new_output(ctx, 8192, state, SeekableOutputStream_write, NULL, SeekableOutputStream_drop); | |
| 152 out->seek = SeekableOutputStream_seek; | |
| 153 out->tell = SeekableOutputStream_tell; | |
| 154 | |
| 155 /* these are now owned by 'out' */ | |
| 156 state = NULL; | |
| 157 stream = NULL; | |
| 158 array = NULL; | |
| 159 | |
| 160 /* out becomes owned by 'wri' as soon as we call, even if it throws. */ | |
| 161 out_temp = out; | |
| 162 out = NULL; | |
| 163 wri = fz_new_document_writer_with_output(ctx, out_temp, format, options); | |
| 164 } | |
| 165 fz_always(ctx) | |
| 166 { | |
| 167 fz_drop_output(ctx, out); | |
| 168 if (options) | |
| 169 (*env)->ReleaseStringUTFChars(env, joptions, options); | |
| 170 if (format) | |
| 171 (*env)->ReleaseStringUTFChars(env, jformat, format); | |
| 172 } | |
| 173 fz_catch(ctx) | |
| 174 jni_rethrow(env, ctx); | |
| 175 | |
| 176 return jlong_cast(wri); | |
| 177 } | |
| 178 | |
| 179 JNIEXPORT jlong JNICALL | |
| 180 FUN(DocumentWriter_newNativeDocumentWriterWithBuffer)(JNIEnv *env, jclass cls, jobject jbuffer, jstring jformat, jstring joptions) | |
| 181 { | |
| 182 fz_context *ctx = get_context(env); | |
| 183 fz_document_writer *wri = NULL; | |
| 184 fz_buffer *buffer = from_Buffer_safe(env, jbuffer); | |
| 185 const char *format = NULL; | |
| 186 const char *options = NULL; | |
| 187 | |
| 188 if (!ctx) return 0; | |
| 189 if (!buffer) jni_throw_arg(env, "output buffer must not be null"); | |
| 190 | |
| 191 if (jformat) | |
| 192 { | |
| 193 format = (*env)->GetStringUTFChars(env, jformat, NULL); | |
| 194 if (!format) | |
| 195 return 0; | |
| 196 } | |
| 197 if (joptions) | |
| 198 { | |
| 199 options = (*env)->GetStringUTFChars(env, joptions, NULL); | |
| 200 if (!options) | |
| 201 { | |
| 202 if (format) | |
| 203 (*env)->ReleaseStringUTFChars(env, jformat, format); | |
| 204 return 0; | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 fz_try(ctx) | |
| 209 wri = fz_new_document_writer_with_buffer(ctx, buffer, format, options); | |
| 210 fz_always(ctx) | |
| 211 { | |
| 212 if (options) | |
| 213 (*env)->ReleaseStringUTFChars(env, joptions, options); | |
| 214 if (format) | |
| 215 (*env)->ReleaseStringUTFChars(env, jformat, format); | |
| 216 } | |
| 217 fz_catch(ctx) | |
| 218 jni_rethrow(env, ctx); | |
| 219 | |
| 220 return jlong_cast(wri); | |
| 221 } | |
| 222 | |
| 223 JNIEXPORT jobject JNICALL | |
| 224 FUN(DocumentWriter_beginPage)(JNIEnv *env, jobject self, jobject jmediabox) | |
| 225 { | |
| 226 fz_context *ctx = get_context(env); | |
| 227 fz_document_writer *wri = from_DocumentWriter(env, self); | |
| 228 fz_rect mediabox = from_Rect(env, jmediabox); | |
| 229 fz_device *device = NULL; | |
| 230 | |
| 231 if (!ctx || !wri) return NULL; | |
| 232 | |
| 233 fz_try(ctx) | |
| 234 device = fz_begin_page(ctx, wri, mediabox); | |
| 235 fz_catch(ctx) | |
| 236 jni_rethrow(env, ctx); | |
| 237 | |
| 238 return to_NativeDevice_safe_own(ctx, env, fz_keep_device(ctx, device)); | |
| 239 } | |
| 240 | |
| 241 JNIEXPORT void JNICALL | |
| 242 FUN(DocumentWriter_endPage)(JNIEnv *env, jobject self) | |
| 243 { | |
| 244 fz_context *ctx = get_context(env); | |
| 245 fz_document_writer *wri = from_DocumentWriter(env, self); | |
| 246 | |
| 247 if (!ctx || !wri) return; | |
| 248 | |
| 249 fz_try(ctx) | |
| 250 fz_end_page(ctx, wri); | |
| 251 fz_catch(ctx) | |
| 252 jni_rethrow_void(env, ctx); | |
| 253 } | |
| 254 | |
| 255 JNIEXPORT void JNICALL | |
| 256 FUN(DocumentWriter_close)(JNIEnv *env, jobject self) | |
| 257 { | |
| 258 fz_context *ctx = get_context(env); | |
| 259 fz_document_writer *wri = from_DocumentWriter(env, self); | |
| 260 | |
| 261 if (!ctx || !wri) return; | |
| 262 | |
| 263 fz_try(ctx) | |
| 264 fz_close_document_writer(ctx, wri); | |
| 265 fz_catch(ctx) | |
| 266 jni_rethrow_void(env, ctx); | |
| 267 } | |
| 268 | |
| 269 static int | |
| 270 jni_ocr_progress(fz_context *ctx, void *arg, int page, int percent) | |
| 271 { | |
| 272 jobject ref = (jobject)arg; | |
| 273 jboolean cancel; | |
| 274 JNIEnv *env = NULL; | |
| 275 jboolean detach = JNI_FALSE; | |
| 276 | |
| 277 if (ref == NULL) | |
| 278 return JNI_FALSE; | |
| 279 | |
| 280 env = jni_attach_thread(&detach); | |
| 281 if (env == NULL) | |
| 282 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot attach to JVM in jni_ocr_progress"); | |
| 283 | |
| 284 cancel = (*env)->CallBooleanMethod(env, ref, mid_DocumentWriter_OCRListener_progress, page, percent); | |
| 285 if ((*env)->ExceptionCheck(env)) | |
| 286 cancel = 1; | |
| 287 | |
| 288 jni_detach_thread(detach); | |
| 289 | |
| 290 return !!cancel; | |
| 291 } | |
| 292 | |
| 293 JNIEXPORT void JNICALL | |
| 294 FUN(DocumentWriter_addOCRListener)(JNIEnv *env, jobject self, jobject jlistener) | |
| 295 { | |
| 296 fz_context *ctx = get_context(env); | |
| 297 fz_document_writer *wri = from_DocumentWriter(env, self); | |
| 298 jobject ref; | |
| 299 | |
| 300 if (!ctx || !wri) return; | |
| 301 | |
| 302 /* Delete any old OCRListener if there is one. */ | |
| 303 ref = (jobject)(*env)->GetLongField(env, self, fid_DocumentWriter_ocrlistener); | |
| 304 if (ref != NULL) | |
| 305 { | |
| 306 (*env)->DeleteGlobalRef(env, ref); | |
| 307 (*env)->SetLongField(env, self, fid_DocumentWriter_ocrlistener, 0); | |
| 308 } | |
| 309 | |
| 310 /* Take a ref and store it for the callback to use */ | |
| 311 ref = (*env)->NewGlobalRef(env, jlistener); | |
| 312 if (!ref) | |
| 313 jni_throw_run_void(env, "cannot take reference to listener"); | |
| 314 (*env)->SetLongField(env, self, fid_DocumentWriter_ocrlistener, jlong_cast(ref)); | |
| 315 | |
| 316 fz_try(ctx) | |
| 317 fz_pdfocr_writer_set_progress(ctx, wri, jni_ocr_progress, ref); | |
| 318 fz_catch(ctx) | |
| 319 { | |
| 320 (*env)->DeleteGlobalRef(env, ref); | |
| 321 (*env)->SetLongField(env, self, fid_DocumentWriter_ocrlistener, 0); | |
| 322 jni_rethrow_void(env, ctx); | |
| 323 } | |
| 324 | |
| 325 } |
