JPEGStream.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #pragma once
  2. #include "closure.h"
  3. #include <jpeglib.h>
  4. #include <jerror.h>
  5. /*
  6. * Expanded data destination object for closure output,
  7. * inspired by IJG's jdatadst.c
  8. */
  9. struct closure_destination_mgr {
  10. jpeg_destination_mgr pub;
  11. JpegClosure* closure;
  12. JOCTET *buffer;
  13. int bufsize;
  14. };
  15. void
  16. init_closure_destination(j_compress_ptr cinfo){
  17. // we really don't have to do anything here
  18. }
  19. boolean
  20. empty_closure_output_buffer(j_compress_ptr cinfo){
  21. Nan::HandleScope scope;
  22. Nan::AsyncResource async("canvas:empty_closure_output_buffer");
  23. closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
  24. v8::Local<v8::Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize).ToLocalChecked();
  25. // emit "data"
  26. v8::Local<v8::Value> argv[2] = {
  27. Nan::Null()
  28. , buf
  29. };
  30. dest->closure->cb.Call(sizeof argv / sizeof *argv, argv, &async);
  31. dest->buffer = (JOCTET *)malloc(dest->bufsize);
  32. cinfo->dest->next_output_byte = dest->buffer;
  33. cinfo->dest->free_in_buffer = dest->bufsize;
  34. return true;
  35. }
  36. void
  37. term_closure_destination(j_compress_ptr cinfo){
  38. Nan::HandleScope scope;
  39. Nan::AsyncResource async("canvas:term_closure_destination");
  40. closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
  41. /* emit remaining data */
  42. v8::Local<v8::Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize - dest->pub.free_in_buffer).ToLocalChecked();
  43. v8::Local<v8::Value> data_argv[2] = {
  44. Nan::Null()
  45. , buf
  46. };
  47. dest->closure->cb.Call(sizeof data_argv / sizeof *data_argv, data_argv, &async);
  48. // emit "end"
  49. v8::Local<v8::Value> end_argv[2] = {
  50. Nan::Null()
  51. , Nan::Null()
  52. };
  53. dest->closure->cb.Call(sizeof end_argv / sizeof *end_argv, end_argv, &async);
  54. }
  55. void
  56. jpeg_closure_dest(j_compress_ptr cinfo, JpegClosure* closure, int bufsize){
  57. closure_destination_mgr * dest;
  58. /* The destination object is made permanent so that multiple JPEG images
  59. * can be written to the same buffer without re-executing jpeg_mem_dest.
  60. */
  61. if (cinfo->dest == NULL) { /* first time for this JPEG object? */
  62. cinfo->dest = (struct jpeg_destination_mgr *)
  63. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  64. sizeof(closure_destination_mgr));
  65. }
  66. dest = (closure_destination_mgr *) cinfo->dest;
  67. cinfo->dest->init_destination = &init_closure_destination;
  68. cinfo->dest->empty_output_buffer = &empty_closure_output_buffer;
  69. cinfo->dest->term_destination = &term_closure_destination;
  70. dest->closure = closure;
  71. dest->bufsize = bufsize;
  72. dest->buffer = (JOCTET *)malloc(bufsize);
  73. cinfo->dest->next_output_byte = dest->buffer;
  74. cinfo->dest->free_in_buffer = dest->bufsize;
  75. }
  76. void encode_jpeg(jpeg_compress_struct cinfo, cairo_surface_t *surface, int quality, bool progressive, int chromaHSampFactor, int chromaVSampFactor) {
  77. int w = cairo_image_surface_get_width(surface);
  78. int h = cairo_image_surface_get_height(surface);
  79. cinfo.in_color_space = JCS_RGB;
  80. cinfo.input_components = 3;
  81. cinfo.image_width = w;
  82. cinfo.image_height = h;
  83. jpeg_set_defaults(&cinfo);
  84. if (progressive)
  85. jpeg_simple_progression(&cinfo);
  86. jpeg_set_quality(&cinfo, quality, (quality < 25) ? 0 : 1);
  87. cinfo.comp_info[0].h_samp_factor = chromaHSampFactor;
  88. cinfo.comp_info[0].v_samp_factor = chromaVSampFactor;
  89. JSAMPROW slr;
  90. jpeg_start_compress(&cinfo, TRUE);
  91. unsigned char *dst;
  92. unsigned int *src = (unsigned int *)cairo_image_surface_get_data(surface);
  93. int sl = 0;
  94. dst = (unsigned char *)malloc(w * 3);
  95. while (sl < h) {
  96. unsigned char *dp = dst;
  97. int x = 0;
  98. while (x < w) {
  99. dp[0] = (*src >> 16) & 255;
  100. dp[1] = (*src >> 8) & 255;
  101. dp[2] = *src & 255;
  102. src++;
  103. dp += 3;
  104. x++;
  105. }
  106. slr = dst;
  107. jpeg_write_scanlines(&cinfo, &slr, 1);
  108. sl++;
  109. }
  110. free(dst);
  111. jpeg_finish_compress(&cinfo);
  112. jpeg_destroy_compress(&cinfo);
  113. }
  114. void
  115. write_to_jpeg_stream(cairo_surface_t *surface, int bufsize, JpegClosure* closure) {
  116. jpeg_compress_struct cinfo;
  117. jpeg_error_mgr jerr;
  118. cinfo.err = jpeg_std_error(&jerr);
  119. jpeg_create_compress(&cinfo);
  120. jpeg_closure_dest(&cinfo, closure, bufsize);
  121. encode_jpeg(
  122. cinfo,
  123. surface,
  124. closure->quality,
  125. closure->progressive,
  126. closure->chromaSubsampling,
  127. closure->chromaSubsampling);
  128. }
  129. void
  130. write_to_jpeg_buffer(cairo_surface_t* surface, JpegClosure* closure) {
  131. jpeg_compress_struct cinfo;
  132. jpeg_error_mgr jerr;
  133. cinfo.err = jpeg_std_error(&jerr);
  134. jpeg_create_compress(&cinfo);
  135. cinfo.client_data = closure;
  136. cinfo.dest = closure->jpeg_dest_mgr;
  137. encode_jpeg(
  138. cinfo,
  139. surface,
  140. closure->quality,
  141. closure->progressive,
  142. closure->chromaSubsampling,
  143. closure->chromaSubsampling);
  144. }