#include "ContentFill.h" #include #include #include static uint32_t next_random(uint32_t *state) { *state = *state * 1664525u + 1013904223u; return *state; } static double match(const uint8_t *pixels, size_t stride, const uint8_t *known, int w, int h, int p, int q, int radius) { int px=p%w, py=p/w, qx=q%w, qy=q/w, count=0; double sum=0; for(int dy=-radius; dy<=radius; ++dy) for(int dx=-radius; dx<=radius; ++dx) { int x=px+dx,y=py+dy,sx=qx+dx,sy=qy+dy; if(x<0||y<0||x>=w||y>=h||sx<0||sy<0||sx>=w||sy>=h||!known[y*w+x]) continue; const uint8_t *a=pixels+y*stride+x*4, *b=pixels+sy*stride+sx*4; for(int c=0;c<4;++c) { int d=a[c]-b[c]; sum+=d*d; } ++count; } return count ? sum/count : DBL_MAX; } int content_fill(uint8_t *pixels, size_t stride, const uint8_t *mask, size_t ms, int w, int h) { size_t n=(size_t)w*h; uint8_t *known=calloc(n,1), *target=calloc(n,1), *valid=calloc(n,1), *queued=calloc(n,1); int *donors=malloc(n*sizeof(int)), *queue=malloc(n*sizeof(int)), *chosen=malloc(n*sizeof(int)); if(!known||!target||!valid||!queued||!donors||!queue||!chosen) { free(known);free(target);free(valid);free(queued);free(donors);free(queue);free(chosen);return -1; } int radius=(w>=5 && h>=5)?2:0; size_t missing=0, donorCount=0, head=0,tail=0, scan=0; // Selected pixels are filled. Unselected opaque pixels are the image to match and copy from; unselected // transparent ones are neither — nothing to match against, and left as they are. for(int y=0;y=w||sy>=h||!known[sy*w+sx]) {ok=0;break;} } if(ok) { valid[p]=1;donors[donorCount++]=p; } } if(!donorCount) goto done; for(int y=0;y=0) q=(chosen[t]>=0?chosen[t]:t)+(p-t); } else q=donors[next_random(&seed)%donorCount]; if(q<0||(size_t)q>=n||!valid[q]) continue; double s=match(pixels,stride,known,w,h,p,q,radius); if(best<0||s=1;r/=2) { int qx=best%w+(int)(next_random(&seed)%(2*r+1))-r; int qy=best/w+(int)(next_random(&seed)%(2*r+1))-r; if(qx<0||qy<0||qx>=w||qy>=h||!valid[qy*w+qx]) continue; int q=qy*w+qx; double s=match(pixels,stride,known,w,h,p,q,radius); if(s=0&&target[q]&&!known[q]&&!queued[q]) {queued[q]=1;queue[tail++]=q;} } } // A selected area that only transparency touches starts from the best random donor, then spreads. while(scan=n) break; queue[tail++]=(int)scan; queued[scan]=1; } done: free(known);free(target);free(valid);free(queued);free(donors);free(queue);free(chosen); return donorCount ? 1 : 0; }