![]() |
Exposure for Plug-in - Printable Version +- Gimp-Forum.net (https://www.gimp-forum.net) +-- Forum: GIMP (https://www.gimp-forum.net/Forum-GIMP) +--- Forum: Extending the GIMP (https://www.gimp-forum.net/Forum-Extending-the-GIMP) +---- Forum: Scripting questions (https://www.gimp-forum.net/Forum-Scripting-questions) +---- Thread: Exposure for Plug-in (/Thread-Exposure-for-Plug-in) Pages:
1
2
|
Exposure for Plug-in - trandoductin - 02-13-2025 There is no pdb call for Exposure setting. How do I do the equivalent? Thank you in advance RE: Exposure for Plug-in - trandoductin - 02-13-2025 I even went as far as trying to read code gegl/exposure.c and can't get it to produce the same here's my python call def simulate_gimp_exposure(img, drawable, black_level=0.002, exposure=1.696): pdb.gimp_image_undo_group_start(img) # Get the current layer layer = drawable # Get the pixel data width, height = layer.width, layer.height srcRgn = layer.get_pixel_rgn(0, 0, width, height, False, False) src_pixels = array("B", srcRgn[0:width, 0:height]) dstRgn = layer.get_pixel_rgn(0, 0, width, height, True, True) p_size = len(srcRgn[0,0]) dest_pixels = array("B", "\x00" * (width * height * p_size)) # white = math.pow(2.0, -exposure) # Equivalent to exp2f(-exposure) # diff = max(white - black_level, 0.000001) # gain = 1.0 / diff # Normalize brightness scaling # **Apply Exposure Negation** (Key part of GIMP logic) exposure_negated = -exposure # ✅ This is how GIMP negates exposure white = math.pow(2.0, exposure_negated) # ✅ Equivalent to exp2f(exposure_negated) # Ensure we don't divide by zero in the gain calculation diff = max(white - black_level, 0.000001) gain = 1.0 / diff # Normalize brightness scaling # Read pixel data as bytes #data = bytearray(srcRgn[0:width, 0:height]) # Convert to mutable array data = src_pixels # Determine number of channels (RGB = 3, RGBA = 4) bpp = len(data) // (width * height) p_size = bpp dest_pixels = array("B", "\x00" * (width * height * p_size)) # Convert to float, apply black level & exposure, and store back exposure_factor = 2**exposure for i in range(0, len(data), bpp): r, g, b = [float(data[i + j])/255.0 for j in range(3)] a = data[i+3] # **Apply GIMP Exposure Math** r = (r - black_level) * gain g = (g - black_level) * gain b = (b - black_level) * gain # Clip values to (0,1) range r, g, b = [min(max(x, 0.0), 1.0) for x in (r, g, b)] # Convert back to 8-bit (0-255) r, g, b = [int(x * 255) for x in (r, g, b)] dest_pixels[i] = r dest_pixels[i+1] = g dest_pixels[i+2] = b dest_pixels[i+3] = a # Copy the whole array back to the pixel region: # Apply modified data back to the image #pixel_rgn[0:width, 0:height] = bytes(data) #pixel_rgn.set_pixels(0, 0, width, height, bytes(data)) dstRgn[0:width, 0:height] = dest_pixels.tostring() #pixel_rgn[0:width, 0:height] = dest_pixels.tostring() layer.flush() layer.merge_shadow(True) layer.update(0, 0, width, height) # Mark the region as modified pdb.gimp_image_undo_group_end(img) pdb.gimp_displays_flush() RE: Exposure for Plug-in - Ofnuts - 02-13-2025 (02-13-2025, 02:42 PM)trandoductin Wrote: There is no pdb call for Exposure setting. It's a GEGL filter. Somewhat easy in GIMP3. In Gimp2, as far as I cant tell the steps are photographic exposure values (aka EV), and one EV is twice as more light. So you convert the value to linear, and multiply by 2^exposure_correction. Of course you don't do this on a pixel basis (unless you have numpy) but you can compute several values for Curves and then apply Curves. I didn't try but you can tell Gimp 2.10 that your plugin understands linear mode (pdb.gimp_plugin_enable_precision()) and this may avoids having to do sRGB<->Linear conversions.Otherwise you can help yourself to my Python code. RE: Exposure for Plug-in - Ofnuts - 02-13-2025 (02-13-2025, 09:29 PM)trandoductin Wrote: I even went as far as trying to read code gegl/exposure.c The code you see is applied on linear values. See my other post. RE: Exposure for Plug-in - trandoductin - 02-14-2025 But the I wrote my python code based on GEGL code as seen below static void process_rgba (GeglOperation *op, void *in_buf, void *out_buf, glong n_pixels, const GeglRectangle *roi, gint level) { GeglProperties *o = GEGL_PROPERTIES (op); gfloat *in_pixel; gfloat *out_pixel; gfloat black_level = (gfloat) o->black_level; gfloat diff; gfloat exposure_negated = (gfloat) -o->exposure; gfloat gain; gfloat white; glong i; in_pixel = in_buf; out_pixel = out_buf; white = exp2f (exposure_negated); diff = MAX (white - black_level, 0.000001); gain = 1.0f / diff; for (i=0; i<n_pixels; i++) { out_pixel[0] = (in_pixel[0] - black_level) * gain; out_pixel[1] = (in_pixel[1] - black_level) * gain; out_pixel[2] = (in_pixel[2] - black_level) * gain; out_pixel[3] = in_pixel[3]; out_pixel += 4; in_pixel += 4; } } Hackathon, Ran my function on a layer and delete half of it. Then ran exposure on the original other half and see how much darker it is. So I used simulate_gimp_exposure(image,layer,0.002,1.696/2.05) #dividing 2.1-ish or 2.05 to match for specific 1.696 exposure. pretty close I hope it's good enough for my client RE: Exposure for Plug-in - Ofnuts - 02-14-2025 (02-14-2025, 12:17 AM)trandoductin Wrote: But the I wrote my python code based on GEGL code as seen below GEGL works on linear values. Nowhere in the code you show does it say that the 0.0 .. 1.0 values are gamma-corrected. Using the spreadsheet functions from the tutorial I linked, I get Gimp's results if I convert to linear first. RE: Exposure for Plug-in - trandoductin - 02-16-2025 Ok this is above my head RE: Exposure for Plug-in - rich2005 - 02-16-2025 Why not use the GEGL filter. One of your other posts here. https://www.gimp-forum.net/Thread-GEGL-kaleidoscope?pid=41869#pid41869 RE: Exposure for Plug-in - Ofnuts - 02-16-2025 (02-16-2025, 03:10 AM)trandoductin Wrote: Ok this is above my head Did you read the tutorial I linked to? RE: Exposure for Plug-in - trandoductin - 02-16-2025 Yeah skimmed it over and something about gamma but their is no gamma in GEGL code that I can see |