Use Perl to Add GIF Image Other Than 8-bit to PDF

≯℡__Kan透↙ 提交于 2019-12-08 01:25:32

Doing one at a time is slow. Doing them all at once takes too much memory for you. Do them a chunk at a time.

my $BUFFER_SIZE = 5 * 50_000;  # Must be a multiple of 5.

my $in_bytes = ...;
my $out_bytes = '';
while (my ($bytes) = $in_bytes =~ s/^(.{1,$BUFFER_SIZE})//s) {
   # Unpack from 5 bit fields.
   my @vals = map { pack('B*', "000$_") } unpack('B*', $bytes) =~ /(.{5})/g;

   # Transform @vals into 8 bit values here.

   # Pack to 8 bit fields.
   $out_bytes .= pack('C*', @vals);

}

Since you're not transforming the values at all (just how they are stored), that simplifies to:

my $BUFFER_SIZE = 5 * 50_000;  # Must be a multiple of 40.

my $in_bytes = ...;
my $out_bytes = '';
while (my ($bytes) = $in_bytes =~ s/^(.{1,$BUFFER_SIZE})//s) {
   # Unpack from 5 bit fields.
   my $bits = unpack('B*', $bytes);
   $bits =~ s/(.{5})/000$1/g;
   $out_bytes .= pack('B*', $bits);

}

You didn't say what to do with the extra bits. I simply ignored them.


Alternative approach with no bit string creation:

my $in_bytes = ...;
my $out_bytes = '';
while (my ($bytes) = $in_bytes =~ s/^(.{1,5})//s) {
    my @bytes = map ord, split //, $bytes;

    # 00000111 11222223 33334444 45555566 66677777

    $out_bytes .= chr(                            (($bytes[0] >> 3) & 0x1F));
    last if @bytes == 1;
    $out_bytes .= chr((($bytes[0] << 2) & 0x1C) | (($bytes[1] >> 6) & 0x03));
    $out_bytes .= chr(                            (($bytes[1] >> 1) & 0x1F));
    last if @bytes == 2;
    $out_bytes .= chr((($bytes[1] << 4) & 0x10) | (($bytes[2] >> 4) & 0x0F));
    last if @bytes == 3;
    $out_bytes .= chr((($bytes[2] << 1) & 0x1E) | (($bytes[3] >> 7) & 0x01));
    $out_bytes .= chr(                            (($bytes[3] >> 2) & 0x1F));
    last if @bytes == 4;
    $out_bytes .= chr((($bytes[3] << 3) & 0x18) | (($bytes[4] >> 5) & 0x07));
    $out_bytes .= chr(                            ( $bytes[4]       & 0x1F));
}

The advantage of the above solution is that it's particularly efficient in C.

STRLEN in_len;
const char* in = SvPVbyte(sv, in_len);

STRLEN out_len = (in_len * 8 / 5) * 8;
char* out = (char*)malloc(out_len);

char* out_cur = out;
char* in_end = in + in_len;

while (in != in_end) {
    *(out_cur++) =                          ((*in >> 3) & 0x1F));
    if (++in == in_end) break;
    *(out_cur++) = ((in[-1] << 2) & 0x1C) | ((*in >> 6) & 0x03));
    *(out_cur++) =                          ((*in >> 1) & 0x1F));
    if (++in == in_end) break;
    *(out_cur++) = ((in[-1] << 4) & 0x10) | ((*in >> 4) & 0x0F));
    if (++in == in_end) break;
    *(out_cur++) = ((in[-1] << 1) & 0x1E) | ((*in >> 7) & 0x01));
    *(out_cur++) =                          ((*in >> 2) & 0x1F));
    if (++in == in_end) break;
    *(out_cur++) = ((in[-1] << 3) & 0x18) | ((*in >> 5) & 0x07));
    *(out_cur++) =                          ( *in       & 0x1F));
}

return newSVpvn(out, out_len);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!