@@ -84,7 +84,9 @@ typedef struct _VipsForeignSaveJxl {
84
84
gboolean lossless ;
85
85
int Q ;
86
86
87
+ #ifdef HAVE_LIBJXL_0_9
87
88
gboolean error ;
89
+ #endif
88
90
89
91
/* JXL multipage and animated images are the same, but multipage has
90
92
* all the frame delays set to -1 (duration 0xffffffff).
@@ -118,6 +120,7 @@ typedef struct _VipsForeignSaveJxl {
118
120
*/
119
121
uint8_t output_buffer [OUTPUT_BUFFER_SIZE ];
120
122
123
+ #ifdef HAVE_LIBJXL_0_9
121
124
/* Chunk reader.
122
125
*/
123
126
struct JxlChunkedFrameInputSource input_source ;
@@ -135,14 +138,21 @@ typedef struct _VipsForeignSaveJxl {
135
138
/* Track number of pixels saved here for eval reporting.
136
139
*/
137
140
guint64 processed ;
138
-
141
+ #else /*!defined(HAVE_LIBJXL_0_9)*/
142
+ /* Buffer scanlines to make a line of libjxl tiles.
143
+ */
144
+ VipsPel * scanline_buffer ;
145
+ size_t scanline_size ;
146
+ int scanline_y ;
147
+ #endif /*defined(HAVE_LIBJXL_0_9)*/
139
148
} VipsForeignSaveJxl ;
140
149
141
150
typedef VipsForeignSaveClass VipsForeignSaveJxlClass ;
142
151
143
152
G_DEFINE_ABSTRACT_TYPE (VipsForeignSaveJxl , vips_foreign_save_jxl ,
144
153
VIPS_TYPE_FOREIGN_SAVE );
145
154
155
+ #ifdef HAVE_LIBJXL_0_9
146
156
static void *
147
157
vips_foreign_save_jxl_get_buffer (void * opaque , size_t * size )
148
158
{
@@ -317,6 +327,7 @@ vips_foreign_save_jxl_set_input_source(VipsForeignSaveJxl *jxl)
317
327
.release_buffer = vips_foreign_save_jxl_input_release_buffer
318
328
};
319
329
}
330
+ #endif /*defined(HAVE_LIBJXL_0_9)*/
320
331
321
332
static void
322
333
vips_foreign_save_jxl_error (VipsForeignSaveJxl * jxl , const char * details )
@@ -437,7 +448,9 @@ vips_foreign_save_jxl_finalize(GObject *gobject)
437
448
VIPS_FREEF (JxlThreadParallelRunnerDestroy , jxl -> runner );
438
449
VIPS_FREEF (JxlEncoderDestroy , jxl -> encoder );
439
450
451
+ #ifdef HAVE_LIBJXL_0_9
440
452
g_mutex_clear (& jxl -> tile_lock );
453
+ #endif
441
454
442
455
G_OBJECT_CLASS (vips_foreign_save_jxl_parent_class )-> finalize (gobject );
443
456
}
@@ -448,7 +461,9 @@ vips_foreign_save_jxl_dispose(GObject *gobject)
448
461
VipsForeignSaveJxl * jxl = (VipsForeignSaveJxl * ) gobject ;
449
462
450
463
VIPS_UNREF (jxl -> target );
464
+ #ifdef HAVE_LIBJXL_0_9
451
465
VIPS_FREEF (g_hash_table_destroy , jxl -> tile_hash );
466
+ #endif
452
467
453
468
G_OBJECT_CLASS (vips_foreign_save_jxl_parent_class )-> dispose (gobject );
454
469
}
@@ -674,6 +689,7 @@ vips_foreign_save_jxl_get_delay(VipsForeignSaveJxl *jxl, int page_number)
674
689
return delay <= 10 ? 100 : delay ;
675
690
}
676
691
692
+ #ifdef HAVE_LIBJXL_0_9
677
693
static int
678
694
vips_foreign_save_jxl_save_page (VipsForeignSaveJxl * jxl ,
679
695
int n , VipsImage * page )
@@ -747,6 +763,142 @@ vips_foreign_save_jxl_save(VipsForeignSaveJxl *jxl, VipsImage *in)
747
763
748
764
return 0 ;
749
765
}
766
+ #else /*!defined(HAVE_LIBJXL_0_9)*/
767
+ /* Output for sequential write.
768
+ */
769
+ static int
770
+ vips_foreign_save_jxl_process_output (VipsForeignSaveJxl * jxl )
771
+ {
772
+ JxlEncoderStatus status ;
773
+
774
+ do {
775
+ uint8_t * out = jxl -> output_buffer ;
776
+ size_t avail_out = OUTPUT_BUFFER_SIZE ;
777
+ status = JxlEncoderProcessOutput (jxl -> encoder , & out , & avail_out );
778
+
779
+ switch (status ) {
780
+ case JXL_ENC_SUCCESS :
781
+ case JXL_ENC_NEED_MORE_OUTPUT :
782
+ if (OUTPUT_BUFFER_SIZE > avail_out &&
783
+ vips_target_write (jxl -> target , jxl -> output_buffer ,
784
+ OUTPUT_BUFFER_SIZE - avail_out ))
785
+ return -1 ;
786
+ break ;
787
+
788
+ default :
789
+ vips_foreign_save_jxl_error (jxl , "JxlEncoderProcessOutput" );
790
+ #ifdef DEBUG
791
+ vips_foreign_save_jxl_print_status (status );
792
+ #endif /*DEBUG*/
793
+ return -1 ;
794
+ }
795
+ } while (status != JXL_ENC_SUCCESS );
796
+
797
+ return 0 ;
798
+ }
799
+
800
+ static int
801
+ vips_foreign_save_jxl_add_frame (VipsForeignSaveJxl * jxl )
802
+ {
803
+ JxlEncoderFrameSettings * frame_settings =
804
+ JxlEncoderFrameSettingsCreate (jxl -> encoder , NULL );
805
+ JxlEncoderFrameSettingsSetOption (frame_settings ,
806
+ JXL_ENC_FRAME_SETTING_DECODING_SPEED , jxl -> tier );
807
+ JxlEncoderSetFrameDistance (frame_settings , jxl -> distance );
808
+ JxlEncoderFrameSettingsSetOption (frame_settings ,
809
+ JXL_ENC_FRAME_SETTING_EFFORT , jxl -> effort );
810
+ JxlEncoderSetFrameLossless (frame_settings , jxl -> lossless );
811
+
812
+ if (jxl -> info .have_animation ) {
813
+ JxlFrameHeader header = { 0 };
814
+
815
+ if (!jxl -> is_animated )
816
+ header .duration = 0xffffffff ;
817
+ else
818
+ header .duration =
819
+ vips_foreign_save_jxl_get_delay (jxl , jxl -> page_number );
820
+
821
+ JxlEncoderSetFrameHeader (frame_settings , & header );
822
+ }
823
+
824
+ if (JxlEncoderAddImageFrame (frame_settings , & jxl -> format ,
825
+ jxl -> scanline_buffer , jxl -> scanline_size )) {
826
+ vips_foreign_save_jxl_error (jxl , "JxlEncoderAddImageFrame" );
827
+ return -1 ;
828
+ }
829
+
830
+ jxl -> page_number += 1 ;
831
+
832
+ /* We should close frames before processing the output
833
+ * if we have written the last frame.
834
+ */
835
+ if (jxl -> page_number == jxl -> page_count )
836
+ JxlEncoderCloseFrames (jxl -> encoder );
837
+
838
+ return vips_foreign_save_jxl_process_output (jxl );
839
+ }
840
+
841
+ /* Another chunk of pixels have arrived from the pipeline. Add to frame, and
842
+ * if the frame completes, compress and write to the target.
843
+ */
844
+ static int
845
+ vips_foreign_save_jxl_sink_disc (VipsRegion * region , VipsRect * area , void * a )
846
+ {
847
+ VipsForeignSaveJxl * jxl = (VipsForeignSaveJxl * ) a ;
848
+ size_t sz = VIPS_IMAGE_SIZEOF_PEL (region -> im ) * area -> width ;
849
+
850
+ /* Write the new pixels into the frame.
851
+ */
852
+ for (int i = 0 ; i < area -> height ; i ++ ) {
853
+ memcpy (jxl -> scanline_buffer + sz * jxl -> scanline_y ,
854
+ VIPS_REGION_ADDR (region , 0 , area -> top + i ),
855
+ sz );
856
+
857
+ jxl -> scanline_y += 1 ;
858
+
859
+ /* If we've filled the frame, add it to the encoder.
860
+ */
861
+ if (jxl -> scanline_y == jxl -> page_height ) {
862
+ if (vips_foreign_save_jxl_add_frame (jxl ))
863
+ return -1 ;
864
+
865
+ jxl -> scanline_y = 0 ;
866
+ }
867
+ }
868
+
869
+ return 0 ;
870
+ }
871
+
872
+ static int
873
+ vips_foreign_save_jxl_save_sequential (VipsForeignSaveJxl * jxl , VipsImage * in )
874
+ {
875
+ /* Write the header.
876
+ */
877
+ if (vips_foreign_save_jxl_process_output (jxl ))
878
+ return -1 ;
879
+
880
+ /* RGB(A) frame as a contiguous buffer.
881
+ */
882
+ jxl -> scanline_size = VIPS_IMAGE_SIZEOF_LINE (in ) * jxl -> page_height ;
883
+ if (!(jxl -> scanline_buffer = vips_tracked_malloc (jxl -> scanline_size )))
884
+ return -1 ;
885
+
886
+ if (vips_sink_disc (in , vips_foreign_save_jxl_sink_disc , jxl ))
887
+ return -1 ;
888
+
889
+ /* This function must be called after the final frame and/or box,
890
+ * otherwise the codestream will not be encoded correctly.
891
+ */
892
+ JxlEncoderCloseInput (jxl -> encoder );
893
+
894
+ /* Flush any remaining libjxl writes.
895
+ */
896
+ if (vips_foreign_save_jxl_process_output (jxl ))
897
+ return -1 ;
898
+
899
+ return 0 ;
900
+ }
901
+ #endif /*defined(HAVE_LIBJXL_0_9)*/
750
902
751
903
static int
752
904
vips_foreign_save_jxl_build (VipsObject * object )
@@ -768,7 +920,13 @@ vips_foreign_save_jxl_build(VipsObject *object)
768
920
* value.
769
921
*/
770
922
if (!vips_object_argument_isset (object , "distance" ))
923
+ #ifdef HAVE_LIBJXL_0_9
771
924
jxl -> distance = JxlEncoderDistanceFromQuality ((float ) jxl -> Q );
925
+ #else
926
+ jxl -> distance = jxl -> Q >= 30
927
+ ? 0.1 + (100 - jxl -> Q ) * 0.09
928
+ : 53.0 / 3000.0 * jxl -> Q * jxl -> Q - 23.0 / 20.0 * jxl -> Q + 25.0 ;
929
+ #endif
772
930
773
931
/* Distance 0 is lossless. libjxl will fail for lossy distance 0.
774
932
*/
@@ -863,6 +1021,7 @@ vips_foreign_save_jxl_build(VipsObject *object)
863
1021
printf (" lossless = %d\n" , jxl -> lossless );
864
1022
#endif /*DEBUG*/
865
1023
1024
+ #ifdef HAVE_LIBJXL_0_9
866
1025
/* _save() is not a vips_sink_*() iterator, so we must emit
867
1026
* the various signals by hand.
868
1027
*/
@@ -876,6 +1035,9 @@ vips_foreign_save_jxl_build(VipsObject *object)
876
1035
877
1036
if (jxl -> error )
878
1037
return -1 ;
1038
+ #else /*!defined(HAVE_LIBJXL_0_9)*/
1039
+ int result = vips_foreign_save_jxl_save_sequential (jxl , in );
1040
+ #endif /*defined(HAVE_LIBJXL_0_9)*/
879
1041
880
1042
if (vips_target_end (jxl -> target ))
881
1043
return -1 ;
@@ -966,7 +1128,9 @@ vips_foreign_save_jxl_init(VipsForeignSaveJxl *jxl)
966
1128
jxl -> distance = 1.0 ;
967
1129
jxl -> effort = 7 ;
968
1130
jxl -> Q = 75 ;
1131
+ #ifdef HAVE_LIBJXL_0_9
969
1132
g_mutex_init (& jxl -> tile_lock );
1133
+ #endif
970
1134
}
971
1135
972
1136
typedef struct _VipsForeignSaveJxlFile {
0 commit comments