@@ -25,7 +25,6 @@ import {
2525 BASELINE_FACTOR ,
2626 BBOX_INIT ,
2727 F32_BBOX_INIT ,
28- FeatureTest ,
2928 info ,
3029 isArrayEqual ,
3130 LINE_DESCENT_FACTOR ,
@@ -62,7 +61,6 @@ import {
6261} from "./default_appearance.js" ;
6362import { DateFormats , TimeFormats } from "../shared/scripting_utils.js" ;
6463import { Dict , isName , isRefsEqual , Name , Ref , RefSet } from "./primitives.js" ;
65- import { Stream , StringStream } from "./stream.js" ;
6664import {
6765 stringToAsciiOrUTF16BE ,
6866 stringToPDFString ,
@@ -72,11 +70,13 @@ import { BaseStream } from "./base_stream.js";
7270import { bidi } from "./bidi.js" ;
7371import { Catalog } from "./catalog.js" ;
7472import { ColorSpaceUtils } from "./colorspace_utils.js" ;
73+ import { createImage } from "./editor/pdf_images.js" ;
7574import { FileSpec } from "./file_spec.js" ;
7675import { JpegStream } from "./jpeg_stream.js" ;
7776import { ObjectLoader } from "./object_loader.js" ;
7877import { OperatorList } from "./operator_list.js" ;
7978import { parseMarkedContentProps } from "./evaluator_utils.js" ;
79+ import { StringStream } from "./stream.js" ;
8080import { XFAFactory } from "./xfa/factory.js" ;
8181
8282class AnnotationFactory {
@@ -351,7 +351,7 @@ class AnnotationFactory {
351351 continue ;
352352 }
353353 imagePromises ||= new Map ( ) ;
354- imagePromises . set ( bitmapId , StampAnnotation . createImage ( bitmap , xref ) ) ;
354+ imagePromises . set ( bitmapId , createImage ( bitmap , xref ) ) ;
355355 }
356356
357357 return imagePromises ;
@@ -427,7 +427,10 @@ class AnnotationFactory {
427427 changes . put ( imageRef , {
428428 data : imageStream ,
429429 } ) ;
430- image . imageStream = image . smaskStream = null ;
430+ image . imageStream = null ;
431+ image . imageRenderStream = null ;
432+ image . smaskStream = null ;
433+ image . smaskRenderStream = null ;
431434 }
432435 promises . push (
433436 StampAnnotation . createNewAnnotation ( xref , annotation , changes , {
@@ -522,12 +525,23 @@ class AnnotationFactory {
522525 ? await imagePromises ?. get ( annotation . bitmapId )
523526 : null ;
524527 if ( image ?. imageStream ) {
525- const { imageStream, smaskStream } = image ;
526- if ( smaskStream ) {
527- imageStream . dict . set ( "SMask" , smaskStream ) ;
528+ const {
529+ imageStream,
530+ imageRenderStream,
531+ smaskStream,
532+ smaskRenderStream,
533+ } = image ;
534+ const imageRef =
535+ imageRenderStream ||
536+ new JpegStream ( imageStream , imageStream . length ) ;
537+ if ( smaskStream || smaskRenderStream ) {
538+ imageRef . dict . set ( "SMask" , smaskRenderStream || smaskStream ) ;
528539 }
529- image . imageRef = new JpegStream ( imageStream , imageStream . length ) ;
530- image . imageStream = image . smaskStream = null ;
540+ image . imageRef = imageRef ;
541+ image . imageStream = null ;
542+ image . imageRenderStream = null ;
543+ image . smaskStream = null ;
544+ image . smaskRenderStream = null ;
531545 }
532546 promises . push (
533547 StampAnnotation . createNewPrintAnnotation (
@@ -5097,82 +5111,6 @@ class StampAnnotation extends MarkupAnnotation {
50975111 return ! modifiedIds ?. has ( this . data . id ) ;
50985112 }
50995113
5100- static async createImage ( bitmap , xref ) {
5101- // TODO: when printing, we could have a specific internal colorspace
5102- // (e.g. something like DeviceRGBA) in order avoid any conversion (i.e. no
5103- // jpeg, no rgba to rgb conversion, etc...)
5104-
5105- const { width, height } = bitmap ;
5106- const canvas = new OffscreenCanvas ( width , height ) ;
5107- const ctx = canvas . getContext ( "2d" , { alpha : true } ) ;
5108-
5109- // Draw the image and get the data in order to extract the transparency.
5110- ctx . drawImage ( bitmap , 0 , 0 ) ;
5111- const data = ctx . getImageData ( 0 , 0 , width , height ) . data ;
5112- const buf32 = new Uint32Array ( data . buffer ) ;
5113- const hasAlpha = buf32 . some (
5114- FeatureTest . isLittleEndian
5115- ? x => x >>> 24 !== 0xff
5116- : x => ( x & 0xff ) !== 0xff
5117- ) ;
5118-
5119- if ( hasAlpha ) {
5120- // Redraw the image on a white background in order to remove the thin gray
5121- // line which can appear when exporting to jpeg.
5122- ctx . fillStyle = "white" ;
5123- ctx . fillRect ( 0 , 0 , width , height ) ;
5124- ctx . drawImage ( bitmap , 0 , 0 ) ;
5125- }
5126-
5127- const jpegBytesPromise = canvas
5128- . convertToBlob ( { type : "image/jpeg" , quality : 1 } )
5129- . then ( blob => blob . bytes ( ) ) ;
5130-
5131- const xobjectName = Name . get ( "XObject" ) ;
5132- const imageName = Name . get ( "Image" ) ;
5133- const image = new Dict ( xref ) ;
5134- image . set ( "Type" , xobjectName ) ;
5135- image . set ( "Subtype" , imageName ) ;
5136- image . set ( "BitsPerComponent" , 8 ) ;
5137- image . setIfName ( "ColorSpace" , "DeviceRGB" ) ;
5138- image . setIfName ( "Filter" , "DCTDecode" ) ;
5139- image . set ( "BBox" , [ 0 , 0 , width , height ] ) ;
5140- image . set ( "Width" , width ) ;
5141- image . set ( "Height" , height ) ;
5142-
5143- let smaskStream = null ;
5144- if ( hasAlpha ) {
5145- const alphaBuffer = new Uint8Array ( buf32 . length ) ;
5146- if ( FeatureTest . isLittleEndian ) {
5147- for ( let i = 0 , ii = buf32 . length ; i < ii ; i ++ ) {
5148- alphaBuffer [ i ] = buf32 [ i ] >>> 24 ;
5149- }
5150- } else {
5151- for ( let i = 0 , ii = buf32 . length ; i < ii ; i ++ ) {
5152- alphaBuffer [ i ] = buf32 [ i ] & 0xff ;
5153- }
5154- }
5155-
5156- const smask = new Dict ( xref ) ;
5157- smask . set ( "Type" , xobjectName ) ;
5158- smask . set ( "Subtype" , imageName ) ;
5159- smask . set ( "BitsPerComponent" , 8 ) ;
5160- smask . setIfName ( "ColorSpace" , "DeviceGray" ) ;
5161- smask . set ( "Width" , width ) ;
5162- smask . set ( "Height" , height ) ;
5163-
5164- smaskStream = new Stream ( alphaBuffer , 0 , 0 , smask ) ;
5165- }
5166- const imageStream = new Stream ( await jpegBytesPromise , 0 , 0 , image ) ;
5167-
5168- return {
5169- imageStream,
5170- smaskStream,
5171- width,
5172- height,
5173- } ;
5174- }
5175-
51765114 static createNewDict ( annotation , xref , { apRef, ap } ) {
51775115 const { date, oldAnnotation, rect, rotation, user } = annotation ;
51785116 const stamp = oldAnnotation || new Dict ( xref ) ;
0 commit comments