ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/CV/CV.xs
(Generate patch)

Comparing CV/CV.xs (file contents):
Revision 1.61 by root, Sun Jul 25 11:24:48 2021 UTC vs.
Revision 1.63 by root, Sun Nov 28 23:26:51 2021 UTC

418 CODE: 418 CODE:
419{ 419{
420 STRLEN data_len; 420 STRLEN data_len;
421 U8 *data = SvPVbyte (image_data, data_len); 421 U8 *data = SvPVbyte (image_data, data_len);
422 static const unsigned char jxl_header[] = { 422 static const unsigned char jxl_header[] = {
423 0, 0, 0, 0x0c, 0x4a, 0x58, 0x4c, 0x20, 423 0, 0, 0, 0x0c, 0x4a, 0x58, 0x4c, 0x20, 0x0d, 0xa, 0x87, 0x0a
424 0x0d, 0xa, 0x87, 0x0a, 0, 0, 0, 0x14,
425 0x66, 0x74, 0x79, 0x70, 0x6a, 0x78, 0x6c, 0x20,
426 0, 0, 0, 0, 0x6a, 0x78, 0x6c, 0x20,
427 }; 424 };
428 425
429 if (data_len >= 20 426 if (data_len >= 20
430 && data[0] == 0xff 427 && data[0] == 0xff
431 && data[1] == 0xd8 428 && data[1] == 0xd8
450 && data[ 5] == 0x0a 447 && data[ 5] == 0x0a
451 && data[ 6] == 0x1a 448 && data[ 6] == 0x1a
452 && data[ 7] == 0x0a) 449 && data[ 7] == 0x0a)
453 RETVAL = "image/png"; 450 RETVAL = "image/png";
454 else if (data_len >= sizeof (jxl_header) && memcmp (data, jxl_header, sizeof (jxl_header)) == 0) 451 else if (data_len >= sizeof (jxl_header) && memcmp (data, jxl_header, sizeof (jxl_header)) == 0)
452 RETVAL = "image/jxl"; // todo: might want to use JxlSignatureCheck
453 else if (data_len >= 2
454 && data[0] == 0xff
455 && data[1] == 0x0a)
455 RETVAL = "image/jxl"; 456 RETVAL = "image/jxl";
456 else if (data_len >= 13 457 else if (data_len >= 13
457 && data[0] == 'G' 458 && data[0] == 'G'
458 && data[1] == 'I' 459 && data[1] == 'I'
459 && data[2] == 'F' 460 && data[2] == 'F'
469 if (data[10] & 0x80) 470 if (data[10] & 0x80)
470 ofs += (1 << ((data[10] & 7) + 1)) * 3; 471 ofs += (1 << ((data[10] & 7) + 1)) * 3;
471 472
472 if (data_len >= ofs + 2 + 1 + 11) 473 if (data_len >= ofs + 2 + 1 + 11)
473 { 474 {
475
474 // skip a rare first graphic control extension block 476 // skip a graphic control extension block. we assume
475 // we assume there is exactly one block 477 // there is at most one such block - while the NAB
478 // has to come firstz, some files do not obey this
476 if (data[ofs] == 0x21 && data[ofs + 1] == 0xf9) 479 if (data[ofs] == 0x21 && data[ofs + 1] == 0xf9)
477 ofs += 3 + data[ofs + 2] + 1; 480 ofs += 3 + data[ofs + 2] + 1;
478 481
479 if (data_len >= ofs + 2 + 1 + 11) 482 if (data_len >= ofs + 2 + 1 + 11)
480 if (!memcmp (data + ofs, "\x21\xff\x0bNETSCAPE2.0", sizeof ("\x21\xff\x0bNETSCAPE2.0") - 1)) 483 if (!memcmp (data + ofs, "\x21\xff\x0bNETSCAPE2.0", sizeof ("\x21\xff\x0bNETSCAPE2.0") - 1))
580GdkPixbuf_noinc * 583GdkPixbuf_noinc *
581decode_jxl (SV *image_data, int thumbnail = 0, int iw = 0, int ih = 0) 584decode_jxl (SV *image_data, int thumbnail = 0, int iw = 0, int ih = 0)
582 CODE: 585 CODE:
583{ 586{
584#if JXL 587#if JXL
585 JxlDecoder *dec = JxlDecoderCreate (0); 588 JxlDecoder *dec;
586 JxlBasicInfo info; 589 JxlBasicInfo info;
587 const uint8_t *next_in = (uint8_t *)SvPVbyte_nolen (image_data); 590 const uint8_t *next_in = (uint8_t *)SvPVbyte_nolen (image_data);
588 size_t avail_in = SvCUR (image_data); 591 size_t avail_in = SvCUR (image_data);
589 const char *error = 0; 592 const char *error = 0;
593 JxlDecoderStatus status;
590 void *runner = 0; 594 void *runner = 0;
591 struct bmff_box box; 595 struct bmff_box box;
592 596
597 RETVAL = 0;
598
593 perlinterp_release (); 599 perlinterp_release ();
594 600
595 RETVAL = 0; 601 dec = JxlDecoderCreate (0);
596 602
597 error = "JxlDecoderCreate failed"; 603 error = "JxlDecoderCreate failed";
598 if (!dec) 604 if (!dec)
599 goto done; 605 goto done;
600 606
601 runner = JxlThreadParallelRunnerCreate (0, JxlThreadParallelRunnerDefaultNumWorkerThreads ()); 607 runner = JxlThreadParallelRunnerCreate (0, JxlThreadParallelRunnerDefaultNumWorkerThreads ());
602 608
609 status = JxlDecoderSetParallelRunner (dec, JxlThreadParallelRunner, runner);
603 error = "JxlDecoderSetParallelRunner failed"; 610 error = "JxlDecoderSetParallelRunner failed";
604 if (JxlDecoderSetParallelRunner (dec, JxlThreadParallelRunner, runner) != JXL_DEC_SUCCESS) 611 if (status != JXL_DEC_SUCCESS)
605 goto done; 612 goto done;
606 613
607 error = "JxlDecoderSubscribeEvents failed"; 614 error = "JxlDecoderSubscribeEvents failed";
608 if (JxlDecoderSubscribeEvents (dec, JXL_DEC_FULL_IMAGE | JXL_DEC_BASIC_INFO) != JXL_DEC_SUCCESS) 615 status = JxlDecoderSubscribeEvents (dec, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE);
616 if (status != JXL_DEC_SUCCESS)
609 goto done; 617 goto done;
610 618
619 status = JxlDecoderSetInput (dec, next_in, avail_in);
611 error = "JxlDecoderSetInput failed"; 620 error = "JxlDecoderSetInput failed";
612 if (JxlDecoderSetInput (dec, next_in, avail_in) != JXL_DEC_SUCCESS) 621 if (status != JXL_DEC_SUCCESS)
613 goto done; 622 goto done;
614 623
615 for (;;) 624 for (;;)
616 { 625 {
617 JxlDecoderStatus status = JxlDecoderProcessInput (dec); 626 status = JxlDecoderProcessInput (dec);
618 627
619 printf ("status %d\n",status);
620
621 switch (status) 628 switch (status)
622 { 629 {
630 case JXL_DEC_FULL_IMAGE:
631 error = 0;
632 goto done;
633
623 case JXL_DEC_ERROR: 634 case JXL_DEC_ERROR:
624 error = "JxlDecoderProcessInput failed"; 635 error = "JxlDecoderProcessInput failed";
625 goto done; 636 goto done;
626 637
627 case JXL_DEC_NEED_MORE_INPUT: 638 case JXL_DEC_NEED_MORE_INPUT:
628 error = "incomplete file"; 639 error = "incomplete file";
629 goto done; 640 goto done;
630 641
631 case JXL_DEC_SUCCESS: 642 case JXL_DEC_SUCCESS:
643 error = "incomplete decode";
632 goto done; 644 goto done;
633 645
634 case JXL_DEC_NEED_IMAGE_OUT_BUFFER: 646 case JXL_DEC_BASIC_INFO:
635 { 647 {
648 status = JxlDecoderGetBasicInfo (dec, &info);
636 error = "JxlDecoderGetBasicInfo failed"; 649 error = "JxlDecoderGetBasicInfo failed";
637 if (JxlDecoderGetBasicInfo (dec, &info) != JXL_DEC_SUCCESS) 650 if (status != JXL_DEC_SUCCESS)
638 goto done; 651 goto done;
639 652
640 RETVAL = gdk_pixbuf_new (GDK_COLORSPACE_RGB, !!info.alpha_bits, 8, info.xsize, info.ysize); 653 RETVAL = gdk_pixbuf_new (GDK_COLORSPACE_RGB, !!info.alpha_bits, 8, info.xsize, info.ysize);
641 error = "unable to allocate pixbuf"; 654 error = "unable to allocate pixbuf";
642 if (!RETVAL) 655 if (!RETVAL)
647 JXL_TYPE_UINT8, 660 JXL_TYPE_UINT8,
648 JXL_NATIVE_ENDIAN, 661 JXL_NATIVE_ENDIAN,
649 gdk_pixbuf_get_rowstride (RETVAL) 662 gdk_pixbuf_get_rowstride (RETVAL)
650 }; 663 };
651 664
665 // cannot use gdk_pixbuf_get_byte_length because that does
666 // not return the size of the buffer, but the size of the buffer without
667 // the last padding bytes. the internal buffer is rowstride * ysize,
668 // and this is what the jxl decoder needs. none of this is documented
669 // in either library, of course.
670
671 status = JxlDecoderSetImageOutBuffer (
672 dec,
673 &format,
674 gdk_pixbuf_get_pixels (RETVAL),
675 gdk_pixbuf_get_rowstride (RETVAL) * info.ysize
676 );
652 error = "JxlDecoderSetImageOutBuffer failed"; 677 error = "JxlDecoderSetImageOutBuffer failed";
653 if (JxlDecoderSetImageOutBuffer (
654 dec,
655 &format,
656 gdk_pixbuf_get_pixels (RETVAL),
657 gdk_pixbuf_get_byte_length (RETVAL)
658 ) != JXL_DEC_SUCCESS) 678 if (status != JXL_DEC_SUCCESS)
659 goto done; 679 goto done;
660 } 680 }
661 break; 681 break;
662 682
663 default: 683 default:
678 if (error) 698 if (error)
679 { 699 {
680 if (RETVAL) 700 if (RETVAL)
681 g_object_unref (RETVAL); 701 g_object_unref (RETVAL);
682 702
683 croak ("load_jxl: %s", error); 703 croak ("load_jxl: %s (status %d)", error, status);
684 } 704 }
685#else 705#else
686 croak ("load_jxl: jpeg-xl not enabled at compile time"); 706 croak ("load_jxl: jpeg-xl not enabled at compile time");
687#endif 707#endif
688} 708}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines