clone

a photo toolkit for your phone that never uploads: fuji film looks for raw files, social crops, error level analysis

main
gudpics / native / core.c
core.c 3.4K
1// Upright browser adapter, 2026-09-21. SPDX-License-Identifier: AGPL-3.0-or-later2// The included extraction retains darktable's and LSD's original notices.3#include "extracted.inc"4static dt_iop_ashift_gui_data_t state;5static dt_iop_module_t module = { &state };6static float result[13]; // angle, vertical shift, horizontal shift, shear, 3x3 forward matrix7static float *flat_lines;89int detect(const uint8_t *rgba, int w, int h) {10 if(w<2 || h<2 || w>1200 || h>1200) return -1;11 free(state.lines); state.lines=NULL; free(flat_lines); flat_lines=NULL;12 memset(&state,0,sizeof(state));13 state.lines_in_width=w; state.lines_in_height=h;14 state.rotation_range=ROTATION_RANGE; state.lensshift_v_range=LENSSHIFT_RANGE;15 state.lensshift_h_range=LENSSHIFT_RANGE; state.shear_range=SHEAR_RANGE;16 float *pixels=malloc((size_t)w*h*4*sizeof(float));17 if(!pixels) return -1;18 for(size_t i=0;i<(size_t)w*h*4;i++) pixels[i]=rgba[i]/255.0f;19 line_detect(pixels,w,h,0,0,1,&state.lines,&state.lines_count,20 &state.vertical_count,&state.horizontal_count,&state.vertical_weight,&state.horizontal_weight,0,FALSE);21 free(pixels);22 srand(42); // Repeatable results for repeated previews of the same photo.23 if(!_remove_outliers(&module)) return -1;24 flat_lines=malloc(MAX(1,state.lines_count)*6*sizeof(float));25 return flat_lines ? state.lines_count : -1;26}2728float *lines(void) {29 if(!flat_lines) return NULL;30 for(int i=0;i<state.lines_count;i++) {31 const dt_iop_ashift_line_t *l=&state.lines[i];32 flat_lines[i*6]=l->p1[0]; flat_lines[i*6+1]=l->p1[1];33 flat_lines[i*6+2]=l->p2[0]; flat_lines[i*6+3]=l->p2[1];34 flat_lines[i*6+4]=l->type; flat_lines[i*6+5]=l->weight;35 }36 return flat_lines;37}3839int fit(int mode) {40 dt_iop_ashift_params_t p={0}; p.mode=ASHIFT_MODE_GENERIC;41 int dir=mode==1?ASHIFT_FIT_VERTICALLY:mode==2?ASHIFT_FIT_HORIZONTALLY:42 mode==3?ASHIFT_FIT_BOTH_SHEAR:ASHIFT_FIT_ROTATION_BOTH_LINES;43 int status=nmsfit(&module,&p,dir);44 if(status) return status;45 if(!isfinite(p.rotation)||!isfinite(p.lensshift_v)||!isfinite(p.lensshift_h)||!isfinite(p.shear)) return NMS_INSANE;46 result[0]=p.rotation; result[1]=p.lensshift_v; result[2]=p.lensshift_h; result[3]=p.shear;47 return 0;48}4950float *matrix(int w,int h,float angle,float vertical,float horizontal,float shear) {51 result[0]=angle;result[1]=vertical;result[2]=horizontal;result[3]=shear;52 _homography(result+4,angle,vertical,horizontal,shear,DEFAULT_F_LENGTH,0,1,w,h,ASHIFT_HOMOGRAPH_FORWARD);53 return result;54}55float *parameters(void) { return result; }5657// Inverse-mapped bilinear browser renderer; independent of darktable's pixelpipe.58int warp(const uint8_t *src,int w,int h,uint8_t *dst,int ow,int oh,const float *inv,59 float left,float top,float cw,float ch) {60 if(w<2||h<2||ow<1||oh<1) return 1;61 for(int y=0;y<oh;y++) for(int x=0;x<ow;x++) {62 const float u=left+(x+0.5f)*cw/ow, v=top+(y+0.5f)*ch/oh;63 const float z=inv[6]*u+inv[7]*v+inv[8];64 const float sx=(inv[0]*u+inv[1]*v+inv[2])/z, sy=(inv[3]*u+inv[4]*v+inv[5])/z;65 uint8_t *o=dst+4*((size_t)y*ow+x);66 if(!isfinite(sx)||!isfinite(sy)||sx<0||sy<0||sx>w-1||sy>h-1) {67 o[0]=o[1]=o[2]=245; o[3]=255; continue;68 }69 int ix=MIN((int)sx,w-2), iy=MIN((int)sy,h-2);70 float fx=sx-ix,fy=sy-iy;71 const uint8_t *p=src+4*((size_t)iy*w+ix);72 for(int c=0;c<3;c++) o[c]=(uint8_t)CLAMP((1-fy)*((1-fx)*p[c]+fx*p[4+c])+fy*((1-fx)*p[w*4+c]+fx*p[w*4+4+c])+0.5f,0,255);73 o[3]=255;74 }75 return 0;76}