Rev 198 | Rev 232 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | toby | 1 | /* |
18 | toby | 2 | This file is part of Filter Foundry, a filter plugin for Adobe Photoshop |
192 | daniel-mar | 3 | Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au |
206 | daniel-mar | 4 | Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft |
2 | toby | 5 | |
6 | This program is free software; you can redistribute it and/or modify |
||
110 | dmarschall | 7 | it under the terms of the GNU General Public License as published by |
2 | toby | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | GNU General Public License for more details. |
||
15 | |||
110 | dmarschall | 16 | You should have received a copy of the GNU General Public License |
2 | toby | 17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | |||
21 | /* This is PLATFORM INDEPENDENT user interface code - mainly dialog logic */ |
||
22 | |||
94 | toby | 23 | #include "preview.h" |
2 | toby | 24 | |
94 | toby | 25 | #ifdef MAC_ENV |
26 | #include <fp.h> |
||
27 | #endif |
||
28 | #include <math.h> |
||
29 | |||
29 | toby | 30 | #include "PIProperties.h" |
2 | toby | 31 | |
94 | toby | 32 | extern FilterRecordPtr gpb; |
2 | toby | 33 | |
34 | PSPixelMap preview_pmap; |
||
35 | PSPixelMask preview_pmask; |
||
36 | Handle preview_handle; |
||
37 | UIRECT preview_rect; |
||
94 | toby | 38 | int preview_w,preview_h,previewerr = false,needall = false,needinput = true; |
2 | toby | 39 | Point preview_scroll; |
40 | Boolean preview_complete = false; |
||
94 | toby | 41 | double zoomfactor,fitzoom; |
2 | toby | 42 | |
94 | toby | 43 | Boolean setup_preview(FilterRecordPtr pb, int nplanes){ |
44 | double zh,zv; |
||
45 | |||
2 | toby | 46 | if(pb->displayPixels && pb->advanceState){ |
157 | dmarschall | 47 | // Possibility 1: Only the part of the preview rect is filled with background color, |
48 | // which can be occupied by image data if zoom factor becomes 100% |
||
49 | /* |
||
155 | dmarschall | 50 | preview_w = MIN(preview_rect.right - preview_rect.left, |
89 | toby | 51 | pb->filterRect.right - pb->filterRect.left); |
155 | dmarschall | 52 | preview_h = MIN(preview_rect.bottom - preview_rect.top, |
89 | toby | 53 | pb->filterRect.bottom - pb->filterRect.top); |
157 | dmarschall | 54 | */ |
55 | // Possibility 2: The whole preview rect is always filled with the background color, |
||
56 | // so you can easily see what is the preview area and what is not |
||
57 | preview_w = preview_rect.right - preview_rect.left; |
||
58 | preview_h = preview_rect.bottom - preview_rect.top; |
||
59 | |||
94 | toby | 60 | zh = (pb->filterRect.right - pb->filterRect.left)/(double)preview_w; |
61 | zv = (pb->filterRect.bottom - pb->filterRect.top)/(double)preview_h; |
||
62 | fitzoom = zh > zv ? zh : zv; |
||
110 | dmarschall | 63 | |
2 | toby | 64 | preview_pmap.version = 1; |
65 | preview_pmap.bounds.left = preview_pmap.bounds.top = 0; |
||
66 | preview_pmap.bounds.right = preview_w; |
||
67 | preview_pmap.bounds.bottom = preview_h; |
||
94 | toby | 68 | preview_pmap.imageMode = pb->imageMode; |
2 | toby | 69 | preview_pmap.rowBytes = nplanes*preview_w; |
70 | preview_pmap.colBytes = nplanes; |
||
71 | preview_pmap.planeBytes = 1; /*interleaved*/ |
||
72 | // preview_pmap.baseAddr = preview_data; |
||
73 | /* baseAddr must be set before using pixelmap */ |
||
110 | dmarschall | 74 | |
2 | toby | 75 | //--------------------------------------------------------------------------- |
76 | // Fields new in version 1: |
||
110 | dmarschall | 77 | //--------------------------------------------------------------------------- |
2 | toby | 78 | preview_pmap.mat = NULL; |
110 | dmarschall | 79 | |
94 | toby | 80 | if( (pb->imageMode == plugInModeRGBColor && nplanes == 4) |
81 | || (pb->imageMode == plugInModeLabColor && nplanes == 4) |
||
82 | || (pb->imageMode == plugInModeGrayScale && nplanes == 2) |
||
83 | || (pb->imageMode == plugInModeDuotone && nplanes == 2) ) |
||
89 | toby | 84 | { |
2 | toby | 85 | preview_pmask.next = NULL; |
86 | // preview_pmask.maskData = preview_data+3; |
||
87 | preview_pmask.rowBytes = preview_pmap.rowBytes; |
||
88 | preview_pmask.colBytes = nplanes; |
||
89 | preview_pmask.maskDescription = kSimplePSMask; |
||
90 | preview_pmap.masks = &preview_pmask; |
||
91 | }else |
||
92 | preview_pmap.masks = NULL; |
||
110 | dmarschall | 93 | |
2 | toby | 94 | preview_handle = PINEWHANDLE((long)preview_h * preview_pmap.rowBytes); |
95 | }else |
||
96 | preview_handle = NULL; |
||
97 | return preview_handle != NULL; |
||
98 | |||
99 | //--------------------------------------------------------------------------- |
||
100 | // Fields new in version 2: |
||
110 | dmarschall | 101 | //--------------------------------------------------------------------------- |
2 | toby | 102 | // preview_pmap.pixelOverlays; |
103 | // preview_pmap.colorManagementOptions; |
||
104 | } |
||
105 | |||
106 | void dispose_preview(){ |
||
107 | if(preview_handle){ |
||
108 | PIDISPOSEHANDLE(preview_handle); |
||
109 | preview_handle = NULL; |
||
110 | } |
||
111 | } |
||
112 | |||
158 | dmarschall | 113 | void* memset_bgcolor(void* ptr, size_t num) { |
157 | dmarschall | 114 | int i; |
189 | dmarschall | 115 | unsigned char* p; |
157 | dmarschall | 116 | |
117 | i = 0; |
||
189 | dmarschall | 118 | p = (unsigned char*)ptr; |
185 | dmarschall | 119 | for (i=0; i<(int)num; ++i) { |
158 | dmarschall | 120 | #ifdef WIN_ENV |
159 | dmarschall | 121 | DWORD color; |
122 | |||
158 | dmarschall | 123 | color = GetSysColor(COLOR_APPWORKSPACE); |
159 | dmarschall | 124 | |
125 | if (gpb->imageMode == plugInModeRGBColor) { |
||
126 | if (i%nplanes == 0) p[i] = GetRValue(color); |
||
127 | if (i%nplanes == 1) p[i] = GetGValue(color); |
||
128 | if (i%nplanes == 2) p[i] = GetBValue(color); |
||
129 | if (i%nplanes == 3) p[i] = 255; // alpha channel |
||
130 | } else if (gpb->imageMode == plugInModeGrayScale) { |
||
189 | dmarschall | 131 | uint8_t r, g, b; |
159 | dmarschall | 132 | |
133 | r = GetRValue(color); |
||
134 | g = GetGValue(color); |
||
135 | b = GetBValue(color); |
||
136 | |||
189 | dmarschall | 137 | if (i%nplanes == 0) p[i] = (uint8_t)(((299L*r)+(587L*g)+(114L*b))/1000); |
159 | dmarschall | 138 | if (i%nplanes == 1) p[i] = 255; // alpha channel |
139 | } else if (gpb->imageMode == plugInModeCMYKColor) { |
||
189 | dmarschall | 140 | uint8_t r, g, b; |
194 | daniel-mar | 141 | double dmax, dr, dg, db, k, c, m, y; |
159 | dmarschall | 142 | |
143 | r = GetRValue(color); |
||
144 | g = GetGValue(color); |
||
145 | b = GetBValue(color); |
||
146 | |||
147 | dr = (double)r / 255; |
||
148 | dg = (double)g / 255; |
||
149 | db = (double)b / 255; |
||
194 | daniel-mar | 150 | |
151 | dmax = dr; |
||
152 | if (dg>dmax) dmax = dg; |
||
153 | if (db>dmax) dmax = db; |
||
154 | |||
155 | k = 1 - dmax; |
||
159 | dmarschall | 156 | c = (1 - dr - k) / (1 - k); |
157 | m = (1 - dg - k) / (1 - k); |
||
158 | y = (1 - db - k) / (1 - k); |
||
159 | |||
189 | dmarschall | 160 | if (i%nplanes == 0) p[i] = (uint8_t)(255 - c * 255); |
161 | if (i%nplanes == 1) p[i] = (uint8_t)(255 - m * 255); |
||
162 | if (i%nplanes == 2) p[i] = (uint8_t)(255 - y * 255); |
||
163 | if (i%nplanes == 3) p[i] = (uint8_t)(255 - k * 255); |
||
159 | dmarschall | 164 | } else { |
165 | // FIXME: If we are in such a non supported color mode, then |
||
166 | // these color codes would be all wrong! |
||
167 | // Just to be safe use (what is probably) white |
||
168 | p[i] = 0xFF; |
||
169 | |||
170 | /* |
||
171 | #define plugInModeBitmap 0 |
||
172 | #define plugInModeGrayScale 1 supported |
||
173 | #define plugInModeIndexedColor 2 |
||
174 | #define plugInModeRGBColor 3 supported |
||
175 | #define plugInModeCMYKColor 4 supported |
||
176 | #define plugInModeHSLColor 5 |
||
177 | #define plugInModeHSBColor 6 |
||
178 | #define plugInModeMultichannel 7 |
||
179 | #define plugInModeDuotone 8 |
||
180 | #define plugInModeLabColor 9 |
||
181 | #define plugInModeGray16 10 |
||
182 | #define plugInModeRGB48 11 |
||
183 | #define plugInModeLab48 12 |
||
184 | #define plugInModeCMYK64 13 |
||
185 | #define plugInModeDeepMultichannel 14 |
||
186 | #define plugInModeDuotone16 15 |
||
187 | #define plugInModeRGB96 16 |
||
188 | #define plugInModeGray32 17 |
||
189 | */ |
||
190 | |||
191 | } |
||
158 | dmarschall | 192 | #else |
193 | // This is the behavior of FilterFoundry <1.7 was this (filled with 0xFF) |
||
194 | // FIXME: Should we do something fancy here, too? |
||
195 | p[i] = 0xFF; |
||
196 | #endif |
||
156 | dmarschall | 197 | } |
198 | return ptr; |
||
199 | } |
||
200 | |||
2 | toby | 201 | void recalc_preview(FilterRecordPtr pb,DIALOGREF dp){ |
202 | OSErr e; |
||
185 | dmarschall | 203 | double scaledw, scaledh; |
204 | int j,n,imgw,imgh; |
||
2 | toby | 205 | Rect r,outRect; |
206 | Ptr outrow; |
||
207 | |||
37 | toby | 208 | preview_complete = false; |
110 | dmarschall | 209 | |
2 | toby | 210 | if(preview_handle){ |
211 | /* size of previewed area, of source image; but no larger than filtered area (selection) */ |
||
212 | scaledw = zoomfactor*preview_w; |
||
213 | if(scaledw > (pb->filterRect.right - pb->filterRect.left)) |
||
89 | toby | 214 | scaledw = pb->filterRect.right - pb->filterRect.left; |
2 | toby | 215 | scaledh = zoomfactor*preview_h; |
216 | if(scaledh > (pb->filterRect.bottom - pb->filterRect.top)) |
||
89 | toby | 217 | scaledh = pb->filterRect.bottom - pb->filterRect.top; |
110 | dmarschall | 218 | |
2 | toby | 219 | /* scale clipped preview area down again - this becomes the pixel size of preview */ |
185 | dmarschall | 220 | imgw = (int)ceil(scaledw/zoomfactor); |
2 | toby | 221 | if(imgw > preview_w) |
222 | imgw = preview_w; |
||
185 | dmarschall | 223 | imgh = (int)ceil(scaledh/zoomfactor); |
2 | toby | 224 | if(imgh > preview_h) |
225 | imgh = preview_h; |
||
226 | |||
227 | /* compute source data rectangle (inRect) */ |
||
228 | |||
229 | /* centre preview on filtered part of input image, adding scroll offset */ |
||
185 | dmarschall | 230 | r.left = (int16)((pb->filterRect.left + pb->filterRect.right - scaledw)/2 + preview_scroll.h); |
2 | toby | 231 | /* make sure it does not go outside the input area */ |
110 | dmarschall | 232 | if(r.left < pb->filterRect.left) { |
120 | dmarschall | 233 | preview_scroll.h += pb->filterRect.left - r.left; |
2 | toby | 234 | r.left = pb->filterRect.left; |
110 | dmarschall | 235 | } |
236 | else if(r.left+scaledw > pb->filterRect.right) { |
||
185 | dmarschall | 237 | preview_scroll.h += (int16)(pb->filterRect.right - (r.left+scaledw)); |
238 | r.left = (int16)(pb->filterRect.right - scaledw); |
||
110 | dmarschall | 239 | } |
185 | dmarschall | 240 | r.right = (int16)(r.left + scaledw); |
241 | preview_pmap.maskPhaseCol = (int32)((preview_scroll.h)/zoomfactor); // phase of the checkerboard |
||
2 | toby | 242 | |
243 | /* now compute for vertical */ |
||
185 | dmarschall | 244 | r.top = (int16)((pb->filterRect.top + pb->filterRect.bottom - scaledh)/2 + preview_scroll.v); |
110 | dmarschall | 245 | if(r.top < pb->filterRect.top) { |
120 | dmarschall | 246 | preview_scroll.v += pb->filterRect.top - r.top; |
2 | toby | 247 | r.top = pb->filterRect.top; |
110 | dmarschall | 248 | } |
249 | else if(r.top+scaledh > pb->filterRect.bottom) { |
||
185 | dmarschall | 250 | preview_scroll.v += (int16)(pb->filterRect.bottom - (r.top+scaledh)); |
251 | r.top = (int16)(pb->filterRect.bottom - scaledh); |
||
110 | dmarschall | 252 | } |
185 | dmarschall | 253 | r.bottom = (int16)(r.top + scaledh); |
254 | preview_pmap.maskPhaseRow = (int32)((preview_scroll.v)/zoomfactor); // phase of the checkerboard |
||
2 | toby | 255 | |
256 | /* if formulae need random access to image - src(), rad() - we must request entire area: */ |
||
94 | toby | 257 | if(needall) |
2 | toby | 258 | SETRECT(pb->inRect,0,0,pb->imageSize.h,pb->imageSize.v); |
94 | toby | 259 | else |
2 | toby | 260 | pb->inRect = r; |
110 | dmarschall | 261 | |
2 | toby | 262 | pb->outRect = pb->inRect; |
263 | SETRECT(pb->maskRect,0,0,0,0); |
||
264 | pb->inLoPlane = pb->outLoPlane = 0; |
||
265 | pb->inHiPlane = pb->outHiPlane = nplanes-1; |
||
37 | toby | 266 | |
2 | toby | 267 | if( !needinput || !(e = pb->advanceState()) ){ |
268 | Ptr outptr = PILOCKHANDLE(preview_handle,false); |
||
53 | toby | 269 | int blankrows = (preview_h - imgh)/2, |
89 | toby | 270 | blankcols = (preview_w - imgw)/2, |
271 | pmrb = preview_pmap.rowBytes; |
||
2 | toby | 272 | |
94 | toby | 273 | evalinit(); |
110 | dmarschall | 274 | |
2 | toby | 275 | SETRECT(outRect,0,0,imgw,imgh); |
110 | dmarschall | 276 | |
53 | toby | 277 | e = process_scaled(pb, false, &r, &outRect, |
278 | outptr + pmrb*blankrows + nplanes*blankcols, pmrb, zoomfactor); |
||
2 | toby | 279 | if(blankrows){ |
157 | dmarschall | 280 | // blank rows on top of preview: |
158 | dmarschall | 281 | memset_bgcolor(outptr, pmrb*blankrows); |
157 | dmarschall | 282 | // blank rows below preview: |
283 | n = preview_h - blankrows - imgh; |
||
158 | dmarschall | 284 | memset_bgcolor(outptr + pmrb*(blankrows+imgh), pmrb*n); |
2 | toby | 285 | } |
286 | if(blankcols){ |
||
157 | dmarschall | 287 | n = preview_w - blankcols - imgw; |
53 | toby | 288 | outrow = outptr + pmrb*blankrows; |
94 | toby | 289 | for(j = blankrows; j < preview_h - blankrows; ++j){ |
157 | dmarschall | 290 | // blank columns on left side of preview (if picture is smaller than the preview area): |
158 | dmarschall | 291 | memset_bgcolor(outrow, nplanes*blankcols); |
157 | dmarschall | 292 | // blank columns on right side of preview (if picture is smaller than the preview area): |
158 | dmarschall | 293 | memset_bgcolor(outrow + nplanes*(blankcols+imgw), nplanes*n); |
53 | toby | 294 | outrow += pmrb; |
2 | toby | 295 | } |
296 | } |
||
297 | |||
298 | if(!e){ |
||
299 | preview_complete = true; |
||
300 | |||
301 | #ifdef WIN_ENV |
||
302 | { |
||
303 | extern HWND preview_hwnd; |
||
304 | HDC hdc = GetDC(preview_hwnd); |
||
89 | toby | 305 | |
2 | toby | 306 | drawpreview(dp,hdc,outptr); |
110 | dmarschall | 307 | |
2 | toby | 308 | ReleaseDC(preview_hwnd,hdc); |
309 | } |
||
310 | #else |
||
311 | { |
||
312 | GrafPtr saveport; |
||
313 | |||
314 | GetPort(&saveport); |
||
315 | SetPortDialogPort(dp); |
||
110 | dmarschall | 316 | |
2 | toby | 317 | drawpreview(dp,NULL,outptr); |
110 | dmarschall | 318 | |
2 | toby | 319 | SetPort(saveport); |
320 | } |
||
321 | #endif |
||
322 | } |
||
323 | |||
324 | PIUNLOCKHANDLE(preview_handle); |
||
94 | toby | 325 | } |
2 | toby | 326 | |
37 | toby | 327 | if(e && !previewerr){ |
198 | daniel-mar | 328 | alertuser(_strdup("Could not build preview at chosen zoom level."), |
329 | e == memFullErr && !needall ? _strdup("The image is too large for available memory. Try zooming in.\nIf that does not help, cancel and retry the filter.") : _strdup("")); |
||
37 | toby | 330 | previewerr = true; |
2 | toby | 331 | } |
37 | toby | 332 | |
2 | toby | 333 | } |
334 | } |
||
335 | |||
336 | OSErr drawpreview(DIALOGREF dp,void *hdc,Ptr imageptr){ |
||
114 | dmarschall | 337 | intptr_t watchsusp; |
2 | toby | 338 | OSErr e = noErr; |
339 | VRect srcRect; |
||
340 | UIRECT imagebounds; |
||
341 | |||
342 | if(preview_handle && preview_complete){ |
||
343 | |||
344 | srcRect = preview_pmap.bounds; |
||
345 | |||
53 | toby | 346 | imagebounds.left = (preview_rect.left + preview_rect.right - preview_w)/2; |
347 | imagebounds.top = (preview_rect.top + preview_rect.bottom - preview_h)/2; |
||
2 | toby | 348 | imagebounds.right = imagebounds.left + preview_w; |
349 | imagebounds.bottom = imagebounds.top + preview_h; |
||
350 | |||
89 | toby | 351 | preview_pmap.baseAddr = imageptr; |
94 | toby | 352 | preview_pmask.maskData = imageptr+3; // FIXME: is this offset correct for all modes?! |
2 | toby | 353 | |
354 | if(gpb->propertyProcs->getPropertyProc){ |
||
355 | gpb->propertyProcs->getPropertyProc(kPhotoshopSignature,propWatchSuspension,0,&watchsusp,NULL); |
||
356 | gpb->propertyProcs->setPropertyProc(kPhotoshopSignature,propWatchSuspension,0,watchsusp+1,NULL); |
||
357 | } |
||
89 | toby | 358 | |
2 | toby | 359 | e = gpb->displayPixels(&preview_pmap,&srcRect,imagebounds.top,imagebounds.left,hdc); |
360 | |||
361 | if(gpb->propertyProcs->getPropertyProc) |
||
362 | gpb->propertyProcs->setPropertyProc(kPhotoshopSignature,propWatchSuspension,0,watchsusp,NULL); |
||
363 | } |
||
364 | return e; |
||
365 | } |