/* BASIC2026 portable PDF text/PDF watermark editor. */
typedef struct {
    const char *type,*text,*pdf_path,*id,*existing,*page_spec,*exclude_spec,*odd_even;
    const char *placement,*repeat,*box_name,*layer,*structure,*blend,*date_format,*time_format;
    double source_page,angle,font_size,min_font_size,opacity,hmargin,vmargin,x,y,hgap,vgap,scale;
    unsigned int color;int auto_shrink,fit_within,x_present,y_present,scale_mode,is_stamp;
} B2026PdfWatermarkSettings;

static const char *b2026_pdf_wm_text(HashVariable *h,const char *jp,const char *en,const char *fallback){const char *v=b2026_pdf_tf_text(h,jp,en);return v!=NULL?v:fallback;}
static int b2026_pdf_wm_number(HashVariable *h,const char *jp,const char *en,double fallback,double *out,int *present){double v=0.0;int p=0;if(!b2026_pdf_tf_number(h,jp,en,&v,&p))return 0;*out=p?v:fallback;if(present!=NULL)*present=p;return 1;}
static int b2026_pdf_wm_settings(HashVariable *h,B2026PdfWatermarkSettings *s,int is_stamp){
    HashEntry *scale_entry,*angle_entry;const char *scale_text=NULL,*angle_text=NULL,*color,*type;double factor,source_page=1.0,searchable=0.0;int p=0,source_present=0,searchable_present=0;memset(s,0,sizeof(*s));s->is_stamp=is_stamp;
    s->text=b2026_pdf_tf_text(h,"文字","text");s->pdf_path=is_stamp?b2026_pdf_tf_text(h,"スタンプPDF","stampPDF"):b2026_pdf_tf_text(h,"透かしPDF","watermarkPDF");if(is_stamp&&s->pdf_path==NULL)s->pdf_path=b2026_pdf_tf_text(h,"透かしPDF","watermarkPDF");type=b2026_pdf_tf_text(h,"種類","type");
    if(s->text!=NULL&&s->pdf_path!=NULL)return 0;if(type==NULL)type=s->pdf_path!=NULL?"PDF":"TEXT";s->type=type;
    if((b2026_strcasecmp(type,"TEXT")==0||strcmp(type,"文字")==0)){if(s->text==NULL)return 0;s->type="TEXT";}
    else if(b2026_strcasecmp(type,"PDF")==0){if(s->pdf_path==NULL)return 0;s->type="PDF";}else return 0;
    s->id=is_stamp?b2026_pdf_tf_text(h,"スタンプID","stampId"):b2026_pdf_tf_text(h,"透かしID","watermarkId");if(is_stamp&&s->id==NULL)s->id=b2026_pdf_tf_text(h,"透かしID","watermarkId");if(s->id==NULL||*s->id=='\0')s->id=is_stamp?"BASIC2026_PAGE_STAMP":"BASIC2026_WATERMARK";
    s->existing=is_stamp?b2026_pdf_tf_text(h,"既存スタンプ","existing"):b2026_pdf_tf_text(h,"既存透かし","existing");if(s->existing==NULL&&is_stamp)s->existing=b2026_pdf_tf_text(h,"既存透かし","existing");if(s->existing==NULL)s->existing="REPLACE";s->page_spec=b2026_pdf_wm_text(h,"対象ページ","pages","ALL");s->exclude_spec=b2026_pdf_tf_text(h,"除外ページ","excludePages");s->odd_even=b2026_pdf_wm_text(h,"偶奇","oddEven","ALL");
    s->placement=b2026_pdf_wm_text(h,"配置","placement","CENTER");s->repeat=b2026_pdf_wm_text(h,"繰り返し","repeat","NONE");s->box_name=b2026_pdf_wm_text(h,"基準ボックス","box","CROP");s->layer=b2026_pdf_wm_text(h,"描画位置","position","FOREGROUND");s->structure=b2026_pdf_wm_text(h,"構造区分","structure","ARTIFACT");s->blend=b2026_pdf_wm_text(h,"合成","blend","NORMAL");s->date_format=b2026_pdf_wm_text(h,"日付書式","dateFormat","%Y-%m-%d");s->time_format=b2026_pdf_wm_text(h,"時刻書式","timeFormat","%H:%M:%S");
    factor=b2026_pdf_tf_unit(h);if(factor<=0.0)return 0;
    if(is_stamp){if(!b2026_pdf_tf_number(h,"スタンプページ","stampPage",&source_page,&source_present))return 0;if(!source_present&&!b2026_pdf_wm_number(h,"透かしページ","watermarkPage",1.0,&source_page,NULL))return 0;}else if(!b2026_pdf_wm_number(h,"透かしページ","watermarkPage",1.0,&source_page,NULL))return 0;s->source_page=source_page;
    if(!b2026_pdf_wm_number(h,"文字サイズ","fontSize",is_stamp?18.0:48.0,&s->font_size,NULL)||!b2026_pdf_wm_number(h,"最小文字サイズ","minFontSize",12.0,&s->min_font_size,NULL)||!b2026_pdf_wm_number(h,"不透明度","opacity",is_stamp?1.0:0.20,&s->opacity,NULL)||!b2026_pdf_wm_number(h,"横余白","horizontalMargin",15.0,&s->hmargin,NULL)||!b2026_pdf_wm_number(h,"縦余白","verticalMargin",15.0,&s->vmargin,NULL)||!b2026_pdf_wm_number(h,"X","x",0.0,&s->x,&s->x_present)||!b2026_pdf_wm_number(h,"Y","y",0.0,&s->y,&s->y_present)||!b2026_pdf_wm_number(h,"横間隔","horizontalGap",80.0,&s->hgap,NULL)||!b2026_pdf_wm_number(h,"縦間隔","verticalGap",60.0,&s->vgap,NULL)||!b2026_pdf_tf_number(h,"検索対象","searchable",&searchable,&searchable_present))return 0;
    if(searchable_present){if(!isfinite(searchable)||(searchable!=0.0&&searchable!=1.0))return 0;s->structure=searchable!=0.0?"CONTENT":"ARTIFACT";}
    angle_entry=b2026_pdf_tf_entry(h,"角度","angle");s->angle=is_stamp?0.0:-45.0;if(angle_entry!=NULL){if(angle_entry->value.type==TYPE_NUMBER){s->angle=angle_entry->value.val.number;}else{angle_text=hash_value_as_text(&angle_entry->value);if(strcmp(angle_text,"左上から右下")==0||b2026_strcasecmp(angle_text,"TOP_LEFT_TO_BOTTOM_RIGHT")==0)s->angle=-45.0;else if(strcmp(angle_text,"左下から右上")==0||b2026_strcasecmp(angle_text,"BOTTOM_LEFT_TO_TOP_RIGHT")==0)s->angle=45.0;else return 0;}}
    s->hmargin*=factor;s->vmargin*=factor;s->x*=factor;s->y*=factor;s->hgap*=factor;s->vgap*=factor;
    s->auto_shrink=!b2026_pdf_tf_entry(h,"自動縮小","autoShrink")||b2026_pdf_tf_true(h,"自動縮小","autoShrink");s->fit_within=!b2026_pdf_tf_entry(h,"ページ内に収める","fitWithinPage")||b2026_pdf_tf_true(h,"ページ内に収める","fitWithinPage");
    color=b2026_pdf_tf_text(h,"文字色","color");if(!b2026_pdf_pd_color(color!=NULL?color:(is_stamp?"#000000":"#808080"),&s->color))return 0;
    scale_entry=b2026_pdf_tf_entry(h,"倍率","scale");s->scale=is_stamp?100.0:50.0;s->scale_mode=0;if(scale_entry!=NULL){if(scale_entry->value.type==TYPE_NUMBER){s->scale=scale_entry->value.val.number;if(!isfinite(s->scale)||s->scale<=0.0)return 0;}else{scale_text=hash_value_as_text(&scale_entry->value);if(b2026_strcasecmp(scale_text,"FIT")==0)s->scale_mode=1;else if(b2026_strcasecmp(scale_text,"WIDTH")==0)s->scale_mode=2;else if(b2026_strcasecmp(scale_text,"HEIGHT")==0)s->scale_mode=3;else return 0;}}
    if(!isfinite(s->source_page)||s->source_page<(double)INT_MIN||s->source_page>(double)INT_MAX||floor(s->source_page)!=s->source_page||!isfinite(s->angle)||s->angle< -360.0||s->angle>360.0||s->font_size<=0.0||s->min_font_size<=0.0||s->min_font_size>s->font_size||s->opacity<0.0||s->opacity>1.0||s->hmargin<0.0||s->vmargin<0.0||s->hgap<0.0||s->vgap<0.0)return 0;
    if(!(b2026_strcasecmp(s->existing,"REPLACE")==0||b2026_strcasecmp(s->existing,"ADD")==0||b2026_strcasecmp(s->existing,"ERROR")==0))return 0;
    if(!(b2026_strcasecmp(s->odd_even,"ALL")==0||strcmp(s->odd_even,"すべて")==0||b2026_strcasecmp(s->odd_even,"ODD")==0||strcmp(s->odd_even,"奇数")==0||b2026_strcasecmp(s->odd_even,"EVEN")==0||strcmp(s->odd_even,"偶数")==0))return 0;
    if(!(b2026_strcasecmp(s->layer,"FOREGROUND")==0||strcmp(s->layer,"前面")==0||b2026_strcasecmp(s->layer,"BACKGROUND")==0||strcmp(s->layer,"背面")==0))return 0;
    if(!(b2026_strcasecmp(s->structure,"ARTIFACT")==0||b2026_strcasecmp(s->structure,"CONTENT")==0))return 0;
    if(!(b2026_strcasecmp(s->blend,"NORMAL")==0||b2026_strcasecmp(s->blend,"MULTIPLY")==0||b2026_strcasecmp(s->blend,"SCREEN")==0))return 0;
    if(!b2026_pdf_tf_box_key(s->box_name,&type))return 0;
    (void)p;return 1;
}

static int b2026_pdf_wm_marker(B2026PdfObject *o,const char *hex_id,int all,int is_stamp){const char *prefix=is_stamp?"%BASIC2026-PAGESTAMP:":"%BASIC2026-WATERMARK:";const unsigned char *p=b2026_pdf_memfind(o->body,o->body_length,prefix,strlen(prefix));size_t n;if(p==NULL)return 0;if(all)return 1;p+=strlen(prefix);n=strlen(hex_id);return (size_t)(o->body+o->body_length-p)>n&&memcmp(p,hex_id,n)==0&&(p[n]=='\r'||p[n]=='\n');}
static int b2026_pdf_wm_contents(B2026PdfDocument *doc,int page,int remove,const char *hex_id,int all,int is_stamp,int *matches){
    B2026PdfObject *o=&doc->objects[page];B2026PdfKeyRange r;B2026PdfTextBuffer out;size_t p,end;memset(&out,0,sizeof(out));if(!b2026_pdf_tf_find_key(o->body,o->body_length,"/Contents",&r))return 0;if(!r.found){*matches=0;return 1;}p=b2026_pdf_tf_space(o->body,o->body_length,r.value_start);end=r.value_end;if(!b2026_pdf_text_append_char(&out,'['))goto fail;
    while(p<end){char *e;long a,g;size_t q,u;int oi,marked;if(o->body[p]=='['||o->body[p]==']'||isspace(o->body[p])){++p;continue;}if(!isdigit(o->body[p]))goto fail;a=strtol((const char*)o->body+p,&e,10);q=b2026_pdf_tf_space(o->body,end,(size_t)(e-(char*)o->body));if(q>=end||!isdigit(o->body[q]))goto fail;g=strtol((const char*)o->body+q,&e,10);u=b2026_pdf_tf_space(o->body,end,(size_t)(e-(char*)o->body));if(u>=end||o->body[u]!='R'||a<=0||a>INT_MAX||g<0||g>INT_MAX||(oi=b2026_pdf_object_lookup(doc,(int)a,(int)g))<0)goto fail;marked=b2026_pdf_wm_marker(&doc->objects[oi],hex_id,all,is_stamp);if(marked){++*matches;if(remove)doc->objects[oi].included=0;}if(!(remove&&marked)){char ref[64];snprintf(ref,sizeof(ref)," %ld %ld R",a,g);if(!b2026_pdf_text_append_bytes(&out,ref,strlen(ref)))goto fail;}p=u+1U;}
    if(!b2026_pdf_text_append_bytes(&out," ]",2U))goto fail;if(remove&&!b2026_pdf_tf_set_key(doc,page,"/Contents",out.data,0))goto fail;free(out.data);return 1;
fail:free(out.data);return 0;
}
static int b2026_pdf_wm_scan(B2026PdfDocument *doc,const char *id,int all,int remove,int is_stamp,int *count){char *hex=b2026_pdf_pd_hex_bytes(id!=NULL?id:"");int i;*count=0;if(hex==NULL)return 0;for(i=0;i<doc->page_count;++i){int n=0;if(!b2026_pdf_wm_contents(doc,doc->page_objects[i],remove,hex,all,is_stamp,&n)){free(hex);return 0;}*count+=n;}free(hex);return 1;}
static int b2026_pdf_wm_selection(B2026PdfDocument *doc,const B2026PdfWatermarkSettings *s,unsigned char **out,int *count){B2026PdfDecorationSettings d;memset(&d,0,sizeof(d));d.page_spec=s->page_spec;d.exclude_spec=s->exclude_spec;d.odd_even=s->odd_even;return b2026_pdf_pd_selection(doc,&d,out,count);}
static int b2026_pdf_wm_box(B2026PdfDocument *doc,int page,const char *name,double box[4]){return b2026_pdf_pd_box(doc,page,name,box);}
static int b2026_pdf_wm_repeat(const char *r,int *rx,int *ry){*rx=*ry=0;if(b2026_strcasecmp(r,"NONE")==0||strcmp(r,"なし")==0)return 1;if(b2026_strcasecmp(r,"HORIZONTAL")==0||strcmp(r,"横")==0){*rx=1;return 1;}if(b2026_strcasecmp(r,"VERTICAL")==0||strcmp(r,"縦")==0){*ry=1;return 1;}if(b2026_strcasecmp(r,"GRID")==0||strcmp(r,"格子")==0){*rx=*ry=1;return 1;}return 0;}
static int b2026_pdf_wm_place(const char *place,double pw,double ph,double bw,double bh,double hm,double vm,double x,double y,int xp,int yp,double *cx,double *cy){
    if((b2026_strcasecmp(place,"COORDINATE")==0||strcmp(place,"座標")==0)){if(!xp||!yp)return 0;*cx=x;*cy=ph-y;return 1;}
    if(b2026_strcasecmp(place,"TOP_LEFT")==0||strcmp(place,"左上")==0){*cx=hm+bw/2.0;*cy=ph-vm-bh/2.0;}
    else if(b2026_strcasecmp(place,"TOP_CENTER")==0||strcmp(place,"上中央")==0){*cx=pw/2.0;*cy=ph-vm-bh/2.0;}
    else if(b2026_strcasecmp(place,"TOP_RIGHT")==0||strcmp(place,"右上")==0){*cx=pw-hm-bw/2.0;*cy=ph-vm-bh/2.0;}
    else if(b2026_strcasecmp(place,"CENTER_LEFT")==0||strcmp(place,"左中央")==0){*cx=hm+bw/2.0;*cy=ph/2.0;}
    else if(b2026_strcasecmp(place,"CENTER")==0||strcmp(place,"中央")==0){*cx=pw/2.0;*cy=ph/2.0;}
    else if(b2026_strcasecmp(place,"CENTER_RIGHT")==0||strcmp(place,"右中央")==0){*cx=pw-hm-bw/2.0;*cy=ph/2.0;}
    else if(b2026_strcasecmp(place,"BOTTOM_LEFT")==0||strcmp(place,"左下")==0){*cx=hm+bw/2.0;*cy=vm+bh/2.0;}
    else if(b2026_strcasecmp(place,"BOTTOM_CENTER")==0||strcmp(place,"下中央")==0){*cx=pw/2.0;*cy=vm+bh/2.0;}
    else if(b2026_strcasecmp(place,"BOTTOM_RIGHT")==0||strcmp(place,"右下")==0){*cx=pw-hm-bw/2.0;*cy=vm+bh/2.0;}else return 0;return 1;
}
static int b2026_pdf_wm_centers(B2026PdfTextBuffer *out,double pw,double ph,double bw,double bh,const B2026PdfWatermarkSettings *s,int *count){
    int rx,ry,ix,iy,nx=1,ny=1;double cx,cy,stepx=bw+s->hgap,stepy=bh+s->vgap;if(!b2026_pdf_wm_repeat(s->repeat,&rx,&ry)||!b2026_pdf_wm_place(s->placement,pw,ph,bw,bh,s->hmargin,s->vmargin,s->x,s->y,s->x_present,s->y_present,&cx,&cy))return 0;if(rx){if(stepx<=0.0)return 0;nx=(int)ceil(pw/stepx)+1;}if(ry){if(stepy<=0.0)return 0;ny=(int)ceil(ph/stepy)+1;}if((long)nx*(long)ny>1024L)return -1;*count=0;for(iy=0;iy<ny;++iy)for(ix=0;ix<nx;++ix){char q[128];double px=rx?fmod(cx,stepx)+ix*stepx:cx,py=ry?fmod(cy,stepy)+iy*stepy:cy;if(px<0.0)px+=stepx;if(py<0.0)py+=stepy;if(px>pw+bw/2.0||py>ph+bh/2.0)continue;snprintf(q,sizeof(q),"%.12g %.12g ",px,py);if(!b2026_pdf_pd_append(out,q))return 0;++*count;}return *count>0?1:0;
}
static int b2026_pdf_wm_emit_text_at(B2026PdfTextBuffer *out,const char *text,double cx,double cy,double angle,double size,double leading,unsigned int color){
    char *copy=b2026_strdup_simple(text),*p;double rad=angle*3.14159265358979323846/180.0,c=cos(rad),sn=sin(rad);int lines=1,index=0;B2026PdfTextBuffer esc;memset(&esc,0,sizeof(esc));if(copy==NULL)return 0;for(p=copy;*p;++p)if(*p=='\n')++lines;{char cmd[256];snprintf(cmd,sizeof(cmd),"q %.12g %.12g %.12g %.12g %.12g %.12g cm\n",c,sn,-sn,c,cx,cy);if(!b2026_pdf_pd_append(out,cmd)){free(copy);return 0;}}
    p=copy;while(p!=NULL){char *nl=strchr(p,'\n'),save=0,*hex;double w=b2026_pdf_pd_width(p,size),yy=((double)(lines-1)/2.0-(double)index)*leading-size*0.35;int nonascii=0,j;char *shown;if(nl!=NULL){save=*nl;*nl='\0';w=b2026_pdf_pd_width(p,size);}shown=p;for(j=0;shown[j];++j)if((unsigned char)shown[j]>=0x80U){nonascii=1;break;}memset(&esc,0,sizeof(esc));if(nonascii){char cmd[1024];hex=b2026_pdf_pd_utf16_hex(shown);if(hex==NULL){free(copy);return 0;}snprintf(cmd,sizeof(cmd),"BT /B2026JP %.6f Tf %.6f %.6f %.6f rg 1 0 0 1 %.6f %.6f Tm <%s> Tj ET\n",size,((color>>16)&255U)/255.0,((color>>8)&255U)/255.0,(color&255U)/255.0,-w/2.0,yy,hex);free(hex);if(!b2026_pdf_pd_append(out,cmd)){free(copy);return 0;}}
        else{const unsigned char *u=(const unsigned char*)shown;char cmd[1024];while(*u){if((*u=='('||*u==')'||*u=='\\')&&!b2026_pdf_text_append_char(&esc,'\\'))goto fail;if(!b2026_pdf_text_append_char(&esc,(char)*u++))goto fail;}snprintf(cmd,sizeof(cmd),"BT /B2026HF %.6f Tf %.6f %.6f %.6f rg 1 0 0 1 %.6f %.6f Tm (%s) Tj ET\n",size,((color>>16)&255U)/255.0,((color>>8)&255U)/255.0,(color&255U)/255.0,-w/2.0,yy,esc.data!=NULL?esc.data:"");free(esc.data);if(!b2026_pdf_pd_append(out,cmd)){free(copy);return 0;}}
        if(nl!=NULL){*nl=save;p=nl+1;}else p=NULL;++index;}
    free(copy);return b2026_pdf_pd_append(out,"Q\n");
fail:free(esc.data);free(copy);return 0;
}
static int b2026_pdf_wm_add_text(B2026PdfDocument *doc,const B2026PdfWatermarkSettings *s,const char *path,unsigned char *selected,int selected_count){
    int latin,japan,gs,i,seq=0,need_japan=0;char *hex=b2026_pdf_pd_hex_bytes(s->id),*title=NULL;time_t now=time(NULL);struct tm lt;char df[128],tf[128],date[128],clock_text[128];B2026PdfDecorationSettings expand;const unsigned char *u=(const unsigned char*)s->text;while(*u)if(*u++>=0x80U){need_japan=1;break;}if(hex==NULL||!b2026_pdf_pd_fonts(doc,s->opacity,need_japan,1,&latin,&japan,&gs)){free(hex);return 0;}if(doc->info_object>=0)title=b2026_pdf_dict_string(doc,doc->objects[doc->info_object].body,doc->objects[doc->info_object].body_length,"/Title");if(title==NULL)title=b2026_strdup_simple("");if(title==NULL){free(hex);return 0;}
#ifdef _WIN32
    localtime_s(&lt,&now);
#else
    {struct tm *tmp=localtime(&now);if(tmp!=NULL)lt=*tmp;else memset(&lt,0,sizeof(lt));}
#endif
    b2026_pdf_pd_time_format(s->date_format,df,sizeof(df));b2026_pdf_pd_time_format(s->time_format,tf,sizeof(tf));if(strftime(date,sizeof(date),df,&lt)==0)date[0]='\0';if(strftime(clock_text,sizeof(clock_text),tf,&lt)==0)clock_text[0]='\0';memset(&expand,0,sizeof(expand));expand.number_format="DECIMAL";expand.digits=0;
    for(i=0;i<doc->page_count;++i)if(selected[i]){int page=doc->page_objects[i],rot=b2026_pdf_page_inherited_integer(doc,page,"/Rotate",0),stream,lines=1,k,center_count=0,rc;double box[4],pw,ph,size=s->font_size,maxw=0.0,th,rad,c,sn,bw,bh,availw,availh,ratio=1.0,a,b,cc,d,e,f;char *expanded,*p,*centers,*cursor,marker[1024],matrix[256];B2026PdfTextBuffer content,centerbuf;++seq;if(!b2026_pdf_wm_box(doc,page,s->box_name,box)){free(hex);free(title);return 0;}rot=((rot%360)+360)%360;pw=(rot==90||rot==270)?box[3]-box[1]:box[2]-box[0];ph=(rot==90||rot==270)?box[2]-box[0]:box[3]-box[1];expanded=b2026_pdf_pd_expand(s->text,i+1,doc->page_count,seq,selected_count,&expand,path,title,date,clock_text);if(expanded==NULL){free(hex);free(title);return 0;}for(p=expanded;*p;++p)if(*p=='\n')++lines;if(lines>16){free(expanded);free(hex);free(title);return -1;}for(p=expanded;;){char *nl=strchr(p,'\n'),save=0;if(nl!=NULL){save=*nl;*nl='\0';}maxw=fmax(maxw,b2026_pdf_pd_width(p,size));if(nl!=NULL){*nl=save;p=nl+1;}else break;}th=size*(1.0+(lines-1)*1.2);rad=s->angle*3.14159265358979323846/180.0;c=fabs(cos(rad));sn=fabs(sin(rad));bw=c*maxw+sn*th;bh=sn*maxw+c*th;availw=pw-2.0*s->hmargin;availh=ph-2.0*s->vmargin;if(s->fit_within&&(bw>availw||bh>availh)){if(!s->auto_shrink||availw<=0.0||availh<=0.0){free(expanded);free(hex);free(title);return -2;}ratio=fmin(availw/bw,availh/bh);size*=ratio;if(size+1e-9<s->min_font_size){free(expanded);free(hex);free(title);return -2;}maxw*=ratio;th*=ratio;bw*=ratio;bh*=ratio;}
        memset(&centerbuf,0,sizeof(centerbuf));rc=b2026_pdf_wm_centers(&centerbuf,pw,ph,bw,bh,s,&center_count);if(rc<=0){free(centerbuf.data);free(expanded);free(hex);free(title);return rc==-1?-3:0;}centers=b2026_pdf_text_take(&centerbuf);memset(&content,0,sizeof(content));snprintf(marker,sizeof(marker),s->is_stamp?"%%BASIC2026-PAGESTAMP:%s\nq\n":"%%BASIC2026-WATERMARK:%s\nq\n",hex);if(!b2026_pdf_pd_append(&content,marker))goto text_fail;b2026_pdf_pd_matrix(rot,box,&a,&b,&cc,&d,&e,&f);snprintf(matrix,sizeof(matrix),"%.12f %.12f %.12f %.12f %.12f %.12f cm\n",a,b,cc,d,e,f);if(!b2026_pdf_pd_append(&content,matrix)||(gs>=0&&!b2026_pdf_pd_append(&content,"/B2026GS gs\n"))||(b2026_strcasecmp(s->structure,"ARTIFACT")==0&&!b2026_pdf_pd_append(&content,"/Artifact BMC\n")))goto text_fail;cursor=centers;for(k=0;k<center_count;++k){char *end;double cx=strtod(cursor,&end),cy;cursor=end;cy=strtod(cursor,&end);cursor=end;if(!b2026_pdf_wm_emit_text_at(&content,expanded,cx,cy,s->angle,size,size*1.2,s->color))goto text_fail;}if((b2026_strcasecmp(s->structure,"ARTIFACT")==0&&!b2026_pdf_pd_append(&content,"EMC\n"))||!b2026_pdf_pd_append(&content,"Q"))goto text_fail;stream=b2026_pdf_tf_add_stream(doc,content.data!=NULL?content.data:"");free(content.data);free(centers);free(expanded);if(stream<0||!b2026_pdf_pd_font_resources(doc,page,doc->objects[latin].old_number,japan>=0?doc->objects[japan].old_number:-1,gs>=0?doc->objects[gs].old_number:-1)||!b2026_pdf_tf_append_contents(doc,page,(b2026_strcasecmp(s->layer,"BACKGROUND")==0||strcmp(s->layer,"背面")==0)?stream:-1,(b2026_strcasecmp(s->layer,"BACKGROUND")==0||strcmp(s->layer,"背面")==0)?-1:stream)){free(hex);free(title);return 0;}continue;
text_fail:free(content.data);free(centers);free(expanded);free(hex);free(title);return 0;}
    free(hex);free(title);return 1;
}

static int b2026_pdf_wm_pdf_form(B2026PdfDocument *target,B2026PdfDocument *source,int page,int **map_out,double box[4],int *rotation,double *uu,int *form_out){
    int *map=NULL,form,num,gen,roi;const unsigned char *cv,*rv;size_t cn,rn;B2026PdfTextBuffer content,res;char dict[1024];memset(&content,0,sizeof(content));memset(&res,0,sizeof(res));if(!b2026_pdf_page_box(source,page,"/CropBox",box)&&!b2026_pdf_page_box(source,page,"/MediaBox",box))return 0;*rotation=b2026_pdf_page_inherited_integer(source,page,"/Rotate",0);if(b2026_pdf_page_direct_number(source,page,"/UserUnit",uu)<=0)*uu=1.0;map=b2026_pdf_tf_import(target,source);if(map==NULL)return 0;if(!b2026_pdf_tf_inherited_value(source,page,"/Contents",&cv,&cn)||!b2026_pdf_tf_collect_content(source,cv,cn,&content,0))goto fail;if(b2026_pdf_tf_inherited_value(source,page,"/Resources",&rv,&rn)){if(b2026_pdf_tf_ref(rv,rn,&num,&gen)&&(roi=b2026_pdf_object_lookup(source,num,gen))>=0){if(!b2026_pdf_tf_rewrite_refs(&res,source->objects[roi].body,source->objects[roi].body_length,source,map))goto fail;}else if(!b2026_pdf_tf_rewrite_refs(&res,rv,rn,source,map))goto fail;}else if(!b2026_pdf_text_append_bytes(&res,"<< >>",5U))goto fail;snprintf(dict,sizeof(dict),"/Type /XObject /Subtype /Form /FormType 1 /BBox [%.17g %.17g %.17g %.17g] /Resources %s",box[0],box[1],box[2],box[3],res.data!=NULL?res.data:"<< >>");form=b2026_pdf_tf_add_stream_bytes(target,dict,(const unsigned char*)(content.data!=NULL?content.data:""),content.used);free(content.data);free(res.data);if(form<0)goto fail2;*map_out=map;*form_out=form;return 1;
fail:free(content.data);free(res.data);fail2:free(map);return 0;
}
static int b2026_pdf_wm_add_pdf(B2026PdfDocument *doc,const B2026PdfWatermarkSettings *s,unsigned char *selected,B2026PdfDocument *source){
    int sp=(int)s->source_page-1,*map=NULL,form=-1,orot=0,i,gs=-1,rx,ry;double ob[4],ouu=1.0;char *hex=b2026_pdf_pd_hex_bytes(s->id);char gsbody[192];const char *bm=b2026_strcasecmp(s->blend,"MULTIPLY")==0?"Multiply":b2026_strcasecmp(s->blend,"SCREEN")==0?"Screen":"Normal";if(sp<0){sp=0;b2026_pdf_log_warning("透かしPDFのページ番号を1ページへ補正しました。 / Watermark PDF page was clamped to page 1.");}if(sp>=source->page_count){sp=source->page_count-1;b2026_pdf_log_warning("透かしPDFのページ番号を最終ページへ補正しました。 / Watermark PDF page was clamped to the last page.");}if(hex==NULL||!b2026_pdf_wm_repeat(s->repeat,&rx,&ry)||!b2026_pdf_wm_pdf_form(doc,source,source->page_objects[sp],&map,ob,&orot,&ouu,&form)){free(hex);free(map);return 0;}snprintf(gsbody,sizeof(gsbody),"<< /Type /ExtGState /ca %.17g /CA %.17g /BM /%s >>",s->opacity,s->opacity,bm);gs=b2026_pdf_tf_add_body(doc,gsbody);if(gs<0){free(hex);free(map);return 0;}
    for(i=0;i<doc->page_count;++i)if(selected[i]){int tp=doc->page_objects[i],trot=b2026_pdf_page_inherited_integer(doc,tp,"/Rotate",0),stream,count=0,k,rc;double tb[4],tuu=1.0,pw,ph,ow,oh,w,h,rad,c,sn,bw,bh,a,b,cc,d,e,f;B2026PdfTextBuffer content,centers;char marker[1024],matrix[256],xname[64],gname[64],*cursor;if(!b2026_pdf_wm_box(doc,tp,s->box_name,tb)){free(hex);free(map);return 0;}if(b2026_pdf_page_direct_number(doc,tp,"/UserUnit",&tuu)<=0)tuu=1.0;trot=((trot%360)+360)%360;orot=((orot%360)+360)%360;pw=(trot==90||trot==270)?tb[3]-tb[1]:tb[2]-tb[0];ph=(trot==90||trot==270)?tb[2]-tb[0]:tb[3]-tb[1];ow=((orot==90||orot==270)?ob[3]-ob[1]:ob[2]-ob[0])*ouu/tuu;oh=((orot==90||orot==270)?ob[2]-ob[0]:ob[3]-ob[1])*ouu/tuu;if(s->scale_mode==1){double z=fmin((pw-2*s->hmargin)/ow,(ph-2*s->vmargin)/oh);w=ow*z;h=oh*z;}else if(s->scale_mode==2){w=pw-2*s->hmargin;h=oh*w/ow;}else if(s->scale_mode==3){h=ph-2*s->vmargin;w=ow*h/oh;}else{w=ow*s->scale/100.0;h=oh*s->scale/100.0;}if(w<=0.0||h<=0.0){free(hex);free(map);return 0;}rad=s->angle*3.14159265358979323846/180.0;c=fabs(cos(rad));sn=fabs(sin(rad));bw=c*w+sn*h;bh=sn*w+c*h;memset(&centers,0,sizeof(centers));rc=b2026_pdf_wm_centers(&centers,pw,ph,bw,bh,s,&count);if(rc<=0){free(centers.data);free(hex);free(map);return rc==-1?-3:0;}snprintf(xname,sizeof(xname),"/B2026Wm%d",doc->objects[form].old_number);snprintf(gname,sizeof(gname),"/B2026Wg%d",doc->objects[gs].old_number);if(!b2026_pdf_tf_make_target_resources(doc,tp,xname,doc->objects[form].old_number,gname,doc->objects[gs].old_number)){free(centers.data);free(hex);free(map);return 0;}memset(&content,0,sizeof(content));snprintf(marker,sizeof(marker),s->is_stamp?"%%BASIC2026-PAGESTAMP:%s\nq\n":"%%BASIC2026-WATERMARK:%s\nq\n",hex);if(!b2026_pdf_pd_append(&content,marker))goto pdf_fail;b2026_pdf_pd_matrix(trot,tb,&a,&b,&cc,&d,&e,&f);snprintf(matrix,sizeof(matrix),"%.12f %.12f %.12f %.12f %.12f %.12f cm\n%s gs\n",a,b,cc,d,e,f,gname);if(!b2026_pdf_pd_append(&content,matrix)||(b2026_strcasecmp(s->structure,"ARTIFACT")==0&&!b2026_pdf_pd_append(&content,"/Artifact BMC\n")))goto pdf_fail;cursor=centers.data;for(k=0;k<count;++k){char *end,payload[512];double cx=strtod(cursor,&end),cy,x,y,p0x,p0y,p1x,p1y,p2x,p2y,scale_x=w/ow,scale_y=h/oh,rcos=cos(rad),rsin=sin(rad),rawx[3],rawy[3];int q;cursor=end;cy=strtod(cursor,&end);cursor=end;x=cx-w/2.0;y=ph-(cy+h/2.0);for(q=0;q<3;++q){double sx=ob[0]+(q==1?1.0:0.0),sy=ob[1]+(q==2?1.0:0.0),u,v,du,dv,uu,vv;b2026_pdf_tf_raw_to_display(orot,ob,sx,sy,&u,&v);u*=ouu/tuu;v*=ouu/tuu;du=x+u*scale_x;dv=ph-y-h+v*scale_y;uu=rcos*(du-cx)-rsin*(dv-cy)+cx;vv=rsin*(du-cx)+rcos*(dv-cy)+cy;b2026_pdf_tf_display_to_raw(0,(double[4]){0,0,pw,ph},uu,vv,&rawx[q],&rawy[q]);}p0x=rawx[0];p0y=rawy[0];p1x=rawx[1];p1y=rawy[1];p2x=rawx[2];p2y=rawy[2];snprintf(payload,sizeof(payload),"%.17g %.17g %.17g %.17g %.17g %.17g cm %s Do\n",p1x-p0x,p1y-p0y,p2x-p0x,p2y-p0y,p0x-(p1x-p0x)*ob[0]-(p2x-p0x)*ob[1],p0y-(p1y-p0y)*ob[0]-(p2y-p0y)*ob[1],xname);if(!b2026_pdf_pd_append(&content,payload))goto pdf_fail;}if((b2026_strcasecmp(s->structure,"ARTIFACT")==0&&!b2026_pdf_pd_append(&content,"EMC\n"))||!b2026_pdf_pd_append(&content,"Q"))goto pdf_fail;stream=b2026_pdf_tf_add_stream(doc,content.data!=NULL?content.data:"");free(content.data);free(centers.data);if(stream<0||!b2026_pdf_tf_append_contents(doc,tp,(b2026_strcasecmp(s->layer,"BACKGROUND")==0||strcmp(s->layer,"背面")==0)?stream:-1,(b2026_strcasecmp(s->layer,"BACKGROUND")==0||strcmp(s->layer,"背面")==0)?-1:stream)){free(hex);free(map);return 0;}continue;
pdf_fail:free(content.data);free(centers.data);free(hex);free(map);return 0;}
    free(hex);free(map);return 1;
}
static int b2026_pdf_wm_verify(const char *path,int pages,const char *id,int all,int present,int is_stamp){B2026PdfDocument d;int rc,count=0;memset(&d,0,sizeof(d));rc=b2026_pdf_load(&d,path,0);if(rc<=0||d.page_count!=pages||!b2026_pdf_wm_scan(&d,id,all,0,is_stamp,&count)){b2026_pdf_document_free(&d);return 0;}b2026_pdf_document_free(&d);return (count>0)==present;}
static const char *b2026_pdf_watermark(const char *operation,int argc,const B2026PdfArg *args){
    int is_stamp=strcmp(operation,"PAGESTAMP")==0||strcmp(operation,"REMOVEPAGESTAMP")==0,remove=strcmp(operation,"REMOVEWATERMARK")==0||strcmp(operation,"REMOVEPAGESTAMP")==0,separate,source_index,rc,i,old=0,removed=0,count=0,remove_all=0;const char *source,*remove_id=NULL,*result;char *output=NULL,*stage=NULL;HashVariable *hash=NULL;B2026PdfWatermarkSettings settings;B2026PdfDocument doc,wm;B2026PdfPageList pages;unsigned char *selected=NULL;memset(&doc,0,sizeof(doc));memset(&wm,0,sizeof(wm));memset(&pages,0,sizeof(pages));
    if(argc!=2&&argc!=3)return b2026_pdf_fail(4230,"","watermark requires path/settings or output/source/settings / 透かしの引数が正しくありません");separate=argc==3;source_index=separate?1:0;if(args[0].kind!=1||(separate&&args[1].kind!=1)||args[argc-1].kind!=3||!b2026_pdf_tf_hash(&args[argc-1],&hash))return b2026_pdf_fail(4230,"","watermark paths/settings are invalid / 透かしのパスまたは設定が正しくありません");source=args[source_index].text;output=b2026_pdf_output_path(args[0].text);if(source==NULL||output==NULL)goto fail;rc=b2026_pdf_load(&doc,source,1);if(rc<=0){b2026_pdf_fail(4231,source,b2026_pdf_load_error(rc));goto fail;}
    if(remove){remove_id=is_stamp?b2026_pdf_tf_text(hash,"スタンプID","stampId"):b2026_pdf_tf_text(hash,"透かしID","watermarkId");if(is_stamp&&remove_id==NULL)remove_id=b2026_pdf_tf_text(hash,"透かしID","watermarkId");remove_all=b2026_pdf_tf_true(hash,"すべて","all");if(!remove_all&&(remove_id==NULL||*remove_id=='\0')){b2026_pdf_fail(4232,source,is_stamp?"stampId or all=1 is required / スタンプIDまたはすべて=1が必要です":"watermarkId or all=1 is required / 透かしIDまたはすべて=1が必要です");goto fail;}if(!b2026_pdf_wm_scan(&doc,remove_id,remove_all,1,is_stamp,&removed))goto memory_fail;if(removed==0){b2026_pdf_fail(4233,source,is_stamp?"specified page stamp was not detected; flattened/rebuilt stamps cannot be removed / 指定されたページスタンプを検出できません。平坦化・再構築されたスタンプは削除できません":"specified watermark was not detected; flattened/rebuilt watermarks cannot be removed / 指定された透かしを検出できません。平坦化・再構築された透かしは削除できません");goto fail;}}
    else{if(!b2026_pdf_wm_settings(hash,&settings,is_stamp)){b2026_pdf_fail(4232,source,is_stamp?"invalid page stamp settings / ページスタンプ設定が正しくありません":"invalid watermark settings / 透かし設定が正しくありません");goto fail;}if(!b2026_pdf_wm_scan(&doc,settings.id,0,0,is_stamp,&old))goto memory_fail;if(old>0&&b2026_strcasecmp(settings.existing,"ERROR")==0){b2026_pdf_fail(4234,source,is_stamp?"page stamp ID already exists / 同じスタンプIDがすでに存在します":"watermark ID already exists / 同じ透かしIDがすでに存在します");goto fail;}if(old>0&&b2026_strcasecmp(settings.existing,"REPLACE")==0&&!b2026_pdf_wm_scan(&doc,settings.id,0,1,is_stamp,&removed))goto memory_fail;if(!b2026_pdf_wm_selection(&doc,&settings,&selected,&count)){b2026_pdf_fail(4235,source,is_stamp?"no page stamp target pages were selected / ページスタンプ対象ページがありません":"no watermark target pages were selected / 透かし対象ページがありません");goto fail;}if(strcmp(settings.type,"TEXT")==0)rc=b2026_pdf_wm_add_text(&doc,&settings,source,selected,count);else{rc=b2026_pdf_load(&wm,settings.pdf_path,1);if(rc<=0){b2026_pdf_fail(4236,settings.pdf_path,b2026_pdf_load_error(rc));goto fail;}rc=b2026_pdf_wm_add_pdf(&doc,&settings,selected,&wm);}if(rc==-1){b2026_pdf_fail(4237,source,"stamp/watermark text exceeds 16 lines / スタンプ／透かし文字列が16行上限を超えています");goto fail;}if(rc==-2){b2026_pdf_fail(4238,source,"stamp/watermark does not fit within the page at the minimum font size / 最小文字サイズでもスタンプ／透かしがページ内に収まりません");goto fail;}if(rc==-3){b2026_pdf_fail(4239,source,"stamp/watermark repetition exceeds 1024 items per page / スタンプ／透かしの繰り返しが1ページ1024個を超えます");goto fail;}if(rc==0)goto memory_fail;}
    for(i=0;i<doc.page_count;++i)if(!b2026_pdf_pages_push(&pages,&doc,doc.page_objects[i],-1))goto memory_fail;stage=b2026_atomic_temp_path(output);if(stage==NULL||!b2026_pdf_write_output(stage,&doc,1,&pages,0,0,0)){if(stage!=NULL)b2026_atomic_discard_file(stage);b2026_pdf_fail(4240,output,is_stamp?"page-stamped PDF could not be written or exceeded 2 GiB / ページスタンプPDFを保存できないか2GiB上限を超えました":"watermarked PDF could not be written or exceeded 2 GiB / 透かしPDFを保存できないか2GiB上限を超えました");goto fail;}if(!b2026_pdf_wm_verify(stage,doc.page_count,remove?remove_id:settings.id,remove?remove_all:0,remove?0:1,is_stamp)){b2026_atomic_discard_file(stage);b2026_pdf_fail(4241,output,is_stamp?"page stamp post-write verification failed / ページスタンプの保存後検証に失敗しました":"watermark post-write verification failed / 透かしの保存後検証に失敗しました");goto fail;}if(!b2026_atomic_commit_file(stage,output)){b2026_atomic_discard_file(stage);b2026_pdf_fail(4242,output,is_stamp?"verified page-stamped PDF could not be committed / 検証済みページスタンプPDFを保存先へ反映できません":"verified watermark PDF could not be committed / 検証済み透かしPDFを保存先へ反映できません");goto fail;}free(stage);stage=NULL;result=runtime_temp_string_copy(output);free(output);free(selected);free(pages.items);b2026_pdf_document_free(&wm);b2026_pdf_document_free(&doc);return result;
memory_fail:b2026_pdf_fail(4199,source,"out of memory or unsupported PDF resources / メモリ不足または未対応のPDF資源です");
fail:if(stage!=NULL){b2026_atomic_discard_file(stage);free(stage);}free(output);free(selected);free(pages.items);b2026_pdf_document_free(&wm);b2026_pdf_document_free(&doc);return runtime_temp_string_copy("");
}
